1 | /***************************************************************************/ |
2 | /* */ |
3 | /* ttpload.c */ |
4 | /* */ |
5 | /* TrueType-specific tables loader (body). */ |
6 | /* */ |
7 | /* Copyright 1996-2018 by */ |
8 | /* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
9 | /* */ |
10 | /* This file is part of the FreeType project, and may only be used, */ |
11 | /* modified, and distributed under the terms of the FreeType project */ |
12 | /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
13 | /* this file you indicate that you have read the license and */ |
14 | /* understand and accept it fully. */ |
15 | /* */ |
16 | /***************************************************************************/ |
17 | |
18 | |
19 | #include <ft2build.h> |
20 | #include FT_INTERNAL_DEBUG_H |
21 | #include FT_INTERNAL_OBJECTS_H |
22 | #include FT_INTERNAL_STREAM_H |
23 | #include FT_TRUETYPE_TAGS_H |
24 | |
25 | #include "ttpload.h" |
26 | |
27 | #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT |
28 | #include "ttgxvar.h" |
29 | #endif |
30 | |
31 | #include "tterrors.h" |
32 | |
33 | |
34 | /*************************************************************************/ |
35 | /* */ |
36 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
37 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ |
38 | /* messages during execution. */ |
39 | /* */ |
40 | #undef FT_COMPONENT |
41 | #define FT_COMPONENT trace_ttpload |
42 | |
43 | |
44 | /*************************************************************************/ |
45 | /* */ |
46 | /* <Function> */ |
47 | /* tt_face_load_loca */ |
48 | /* */ |
49 | /* <Description> */ |
50 | /* Load the locations table. */ |
51 | /* */ |
52 | /* <InOut> */ |
53 | /* face :: A handle to the target face object. */ |
54 | /* */ |
55 | /* <Input> */ |
56 | /* stream :: The input stream. */ |
57 | /* */ |
58 | /* <Return> */ |
59 | /* FreeType error code. 0 means success. */ |
60 | /* */ |
61 | FT_LOCAL_DEF( FT_Error ) |
62 | tt_face_load_loca( TT_Face face, |
63 | FT_Stream stream ) |
64 | { |
65 | FT_Error error; |
66 | FT_ULong table_len; |
67 | FT_Int shift; |
68 | |
69 | |
70 | /* we need the size of the `glyf' table for malformed `loca' tables */ |
71 | error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len ); |
72 | |
73 | /* it is possible that a font doesn't have a glyf table at all */ |
74 | /* or its size is zero */ |
75 | if ( FT_ERR_EQ( error, Table_Missing ) ) |
76 | { |
77 | face->glyf_len = 0; |
78 | face->glyf_offset = 0; |
79 | } |
80 | else if ( error ) |
81 | goto Exit; |
82 | else |
83 | { |
84 | #ifdef FT_CONFIG_OPTION_INCREMENTAL |
85 | if ( face->root.internal->incremental_interface ) |
86 | face->glyf_offset = 0; |
87 | else |
88 | #endif |
89 | face->glyf_offset = FT_STREAM_POS(); |
90 | } |
91 | |
92 | FT_TRACE2(( "Locations " )); |
93 | error = face->goto_table( face, TTAG_loca, stream, &table_len ); |
94 | if ( error ) |
95 | { |
96 | error = FT_THROW( Locations_Missing ); |
97 | goto Exit; |
98 | } |
99 | |
100 | if ( face->header.Index_To_Loc_Format != 0 ) |
101 | { |
102 | shift = 2; |
103 | |
104 | if ( table_len >= 0x40000L ) |
105 | { |
106 | FT_TRACE2(( "table too large\n" )); |
107 | table_len = 0x3FFFFL; |
108 | } |
109 | face->num_locations = table_len >> shift; |
110 | } |
111 | else |
112 | { |
113 | shift = 1; |
114 | |
115 | if ( table_len >= 0x20000L ) |
116 | { |
117 | FT_TRACE2(( "table too large\n" )); |
118 | table_len = 0x1FFFFL; |
119 | } |
120 | face->num_locations = table_len >> shift; |
121 | } |
122 | |
123 | if ( face->num_locations != (FT_ULong)face->root.num_glyphs + 1 ) |
124 | { |
125 | FT_TRACE2(( "glyph count mismatch! loca: %d, maxp: %d\n" , |
126 | face->num_locations - 1, face->root.num_glyphs )); |
127 | |
128 | /* we only handle the case where `maxp' gives a larger value */ |
129 | if ( face->num_locations <= (FT_ULong)face->root.num_glyphs ) |
130 | { |
131 | FT_ULong new_loca_len = |
132 | ( (FT_ULong)face->root.num_glyphs + 1 ) << shift; |
133 | |
134 | TT_Table entry = face->dir_tables; |
135 | TT_Table limit = entry + face->num_tables; |
136 | |
137 | FT_Long pos = (FT_Long)FT_STREAM_POS(); |
138 | FT_Long dist = 0x7FFFFFFFL; |
139 | FT_Bool found = 0; |
140 | |
141 | |
142 | /* compute the distance to next table in font file */ |
143 | for ( ; entry < limit; entry++ ) |
144 | { |
145 | FT_Long diff = (FT_Long)entry->Offset - pos; |
146 | |
147 | |
148 | if ( diff > 0 && diff < dist ) |
149 | { |
150 | dist = diff; |
151 | found = 1; |
152 | } |
153 | } |
154 | |
155 | if ( !found ) |
156 | { |
157 | /* `loca' is the last table */ |
158 | dist = (FT_Long)stream->size - pos; |
159 | } |
160 | |
161 | if ( new_loca_len <= (FT_ULong)dist ) |
162 | { |
163 | face->num_locations = (FT_ULong)face->root.num_glyphs + 1; |
164 | table_len = new_loca_len; |
165 | |
166 | FT_TRACE2(( "adjusting num_locations to %d\n" , |
167 | face->num_locations )); |
168 | } |
169 | else |
170 | { |
171 | face->root.num_glyphs = face->num_locations |
172 | ? (FT_Long)face->num_locations - 1 : 0; |
173 | |
174 | FT_TRACE2(( "adjusting num_glyphs to %d\n" , |
175 | face->root.num_glyphs )); |
176 | } |
177 | } |
178 | } |
179 | |
180 | /* |
181 | * Extract the frame. We don't need to decompress it since |
182 | * we are able to parse it directly. |
183 | */ |
184 | if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) ) |
185 | goto Exit; |
186 | |
187 | FT_TRACE2(( "loaded\n" )); |
188 | |
189 | Exit: |
190 | return error; |
191 | } |
192 | |
193 | |
194 | FT_LOCAL_DEF( FT_ULong ) |
195 | tt_face_get_location( TT_Face face, |
196 | FT_UInt gindex, |
197 | FT_UInt *asize ) |
198 | { |
199 | FT_ULong pos1, pos2; |
200 | FT_Byte* p; |
201 | FT_Byte* p_limit; |
202 | |
203 | |
204 | pos1 = pos2 = 0; |
205 | |
206 | if ( gindex < face->num_locations ) |
207 | { |
208 | if ( face->header.Index_To_Loc_Format != 0 ) |
209 | { |
210 | p = face->glyph_locations + gindex * 4; |
211 | p_limit = face->glyph_locations + face->num_locations * 4; |
212 | |
213 | pos1 = FT_NEXT_ULONG( p ); |
214 | pos2 = pos1; |
215 | |
216 | if ( p + 4 <= p_limit ) |
217 | pos2 = FT_NEXT_ULONG( p ); |
218 | } |
219 | else |
220 | { |
221 | p = face->glyph_locations + gindex * 2; |
222 | p_limit = face->glyph_locations + face->num_locations * 2; |
223 | |
224 | pos1 = FT_NEXT_USHORT( p ); |
225 | pos2 = pos1; |
226 | |
227 | if ( p + 2 <= p_limit ) |
228 | pos2 = FT_NEXT_USHORT( p ); |
229 | |
230 | pos1 <<= 1; |
231 | pos2 <<= 1; |
232 | } |
233 | } |
234 | |
235 | /* Check broken location data. */ |
236 | if ( pos1 > face->glyf_len ) |
237 | { |
238 | FT_TRACE1(( "tt_face_get_location:" |
239 | " too large offset (0x%08lx) found for glyph index %ld,\n" |
240 | " " |
241 | " exceeding the end of `glyf' table (0x%08lx)\n" , |
242 | pos1, gindex, face->glyf_len )); |
243 | *asize = 0; |
244 | return 0; |
245 | } |
246 | |
247 | if ( pos2 > face->glyf_len ) |
248 | { |
249 | /* We try to sanitize the last `loca' entry. */ |
250 | if ( gindex == face->num_locations - 2 ) |
251 | { |
252 | FT_TRACE1(( "tt_face_get_location:" |
253 | " too large size (%ld bytes) found for glyph index %ld,\n" |
254 | " " |
255 | " truncating at the end of `glyf' table to %ld bytes\n" , |
256 | pos2 - pos1, gindex, face->glyf_len - pos1 )); |
257 | pos2 = face->glyf_len; |
258 | } |
259 | else |
260 | { |
261 | FT_TRACE1(( "tt_face_get_location:" |
262 | " too large offset (0x%08lx) found for glyph index %ld,\n" |
263 | " " |
264 | " exceeding the end of `glyf' table (0x%08lx)\n" , |
265 | pos2, gindex + 1, face->glyf_len )); |
266 | *asize = 0; |
267 | return 0; |
268 | } |
269 | } |
270 | |
271 | /* The `loca' table must be ordered; it refers to the length of */ |
272 | /* an entry as the difference between the current and the next */ |
273 | /* position. However, there do exist (malformed) fonts which */ |
274 | /* don't obey this rule, so we are only able to provide an */ |
275 | /* upper bound for the size. */ |
276 | /* */ |
277 | /* We get (intentionally) a wrong, non-zero result in case the */ |
278 | /* `glyf' table is missing. */ |
279 | if ( pos2 >= pos1 ) |
280 | *asize = (FT_UInt)( pos2 - pos1 ); |
281 | else |
282 | *asize = (FT_UInt)( face->glyf_len - pos1 ); |
283 | |
284 | return pos1; |
285 | } |
286 | |
287 | |
288 | FT_LOCAL_DEF( void ) |
289 | tt_face_done_loca( TT_Face face ) |
290 | { |
291 | FT_Stream stream = face->root.stream; |
292 | |
293 | |
294 | FT_FRAME_RELEASE( face->glyph_locations ); |
295 | face->num_locations = 0; |
296 | } |
297 | |
298 | |
299 | |
300 | /*************************************************************************/ |
301 | /* */ |
302 | /* <Function> */ |
303 | /* tt_face_load_cvt */ |
304 | /* */ |
305 | /* <Description> */ |
306 | /* Load the control value table into a face object. */ |
307 | /* */ |
308 | /* <InOut> */ |
309 | /* face :: A handle to the target face object. */ |
310 | /* */ |
311 | /* <Input> */ |
312 | /* stream :: A handle to the input stream. */ |
313 | /* */ |
314 | /* <Return> */ |
315 | /* FreeType error code. 0 means success. */ |
316 | /* */ |
317 | FT_LOCAL_DEF( FT_Error ) |
318 | tt_face_load_cvt( TT_Face face, |
319 | FT_Stream stream ) |
320 | { |
321 | #ifdef TT_USE_BYTECODE_INTERPRETER |
322 | |
323 | FT_Error error; |
324 | FT_Memory memory = stream->memory; |
325 | FT_ULong table_len; |
326 | |
327 | |
328 | FT_TRACE2(( "CVT " )); |
329 | |
330 | error = face->goto_table( face, TTAG_cvt, stream, &table_len ); |
331 | if ( error ) |
332 | { |
333 | FT_TRACE2(( "is missing\n" )); |
334 | |
335 | face->cvt_size = 0; |
336 | face->cvt = NULL; |
337 | error = FT_Err_Ok; |
338 | |
339 | goto Exit; |
340 | } |
341 | |
342 | face->cvt_size = table_len / 2; |
343 | |
344 | if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) ) |
345 | goto Exit; |
346 | |
347 | if ( FT_FRAME_ENTER( face->cvt_size * 2L ) ) |
348 | goto Exit; |
349 | |
350 | { |
351 | FT_Short* cur = face->cvt; |
352 | FT_Short* limit = cur + face->cvt_size; |
353 | |
354 | |
355 | for ( ; cur < limit; cur++ ) |
356 | *cur = FT_GET_SHORT(); |
357 | } |
358 | |
359 | FT_FRAME_EXIT(); |
360 | FT_TRACE2(( "loaded\n" )); |
361 | |
362 | #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT |
363 | if ( face->doblend ) |
364 | error = tt_face_vary_cvt( face, stream ); |
365 | #endif |
366 | |
367 | Exit: |
368 | return error; |
369 | |
370 | #else /* !TT_USE_BYTECODE_INTERPRETER */ |
371 | |
372 | FT_UNUSED( face ); |
373 | FT_UNUSED( stream ); |
374 | |
375 | return FT_Err_Ok; |
376 | |
377 | #endif |
378 | } |
379 | |
380 | |
381 | /*************************************************************************/ |
382 | /* */ |
383 | /* <Function> */ |
384 | /* tt_face_load_fpgm */ |
385 | /* */ |
386 | /* <Description> */ |
387 | /* Load the font program. */ |
388 | /* */ |
389 | /* <InOut> */ |
390 | /* face :: A handle to the target face object. */ |
391 | /* */ |
392 | /* <Input> */ |
393 | /* stream :: A handle to the input stream. */ |
394 | /* */ |
395 | /* <Return> */ |
396 | /* FreeType error code. 0 means success. */ |
397 | /* */ |
398 | FT_LOCAL_DEF( FT_Error ) |
399 | tt_face_load_fpgm( TT_Face face, |
400 | FT_Stream stream ) |
401 | { |
402 | #ifdef TT_USE_BYTECODE_INTERPRETER |
403 | |
404 | FT_Error error; |
405 | FT_ULong table_len; |
406 | |
407 | |
408 | FT_TRACE2(( "Font program " )); |
409 | |
410 | /* The font program is optional */ |
411 | error = face->goto_table( face, TTAG_fpgm, stream, &table_len ); |
412 | if ( error ) |
413 | { |
414 | face->font_program = NULL; |
415 | face->font_program_size = 0; |
416 | error = FT_Err_Ok; |
417 | |
418 | FT_TRACE2(( "is missing\n" )); |
419 | } |
420 | else |
421 | { |
422 | face->font_program_size = table_len; |
423 | if ( FT_FRAME_EXTRACT( table_len, face->font_program ) ) |
424 | goto Exit; |
425 | |
426 | FT_TRACE2(( "loaded, %12d bytes\n" , face->font_program_size )); |
427 | } |
428 | |
429 | Exit: |
430 | return error; |
431 | |
432 | #else /* !TT_USE_BYTECODE_INTERPRETER */ |
433 | |
434 | FT_UNUSED( face ); |
435 | FT_UNUSED( stream ); |
436 | |
437 | return FT_Err_Ok; |
438 | |
439 | #endif |
440 | } |
441 | |
442 | |
443 | /*************************************************************************/ |
444 | /* */ |
445 | /* <Function> */ |
446 | /* tt_face_load_prep */ |
447 | /* */ |
448 | /* <Description> */ |
449 | /* Load the cvt program. */ |
450 | /* */ |
451 | /* <InOut> */ |
452 | /* face :: A handle to the target face object. */ |
453 | /* */ |
454 | /* <Input> */ |
455 | /* stream :: A handle to the input stream. */ |
456 | /* */ |
457 | /* <Return> */ |
458 | /* FreeType error code. 0 means success. */ |
459 | /* */ |
460 | FT_LOCAL_DEF( FT_Error ) |
461 | tt_face_load_prep( TT_Face face, |
462 | FT_Stream stream ) |
463 | { |
464 | #ifdef TT_USE_BYTECODE_INTERPRETER |
465 | |
466 | FT_Error error; |
467 | FT_ULong table_len; |
468 | |
469 | |
470 | FT_TRACE2(( "Prep program " )); |
471 | |
472 | error = face->goto_table( face, TTAG_prep, stream, &table_len ); |
473 | if ( error ) |
474 | { |
475 | face->cvt_program = NULL; |
476 | face->cvt_program_size = 0; |
477 | error = FT_Err_Ok; |
478 | |
479 | FT_TRACE2(( "is missing\n" )); |
480 | } |
481 | else |
482 | { |
483 | face->cvt_program_size = table_len; |
484 | if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) ) |
485 | goto Exit; |
486 | |
487 | FT_TRACE2(( "loaded, %12d bytes\n" , face->cvt_program_size )); |
488 | } |
489 | |
490 | Exit: |
491 | return error; |
492 | |
493 | #else /* !TT_USE_BYTECODE_INTERPRETER */ |
494 | |
495 | FT_UNUSED( face ); |
496 | FT_UNUSED( stream ); |
497 | |
498 | return FT_Err_Ok; |
499 | |
500 | #endif |
501 | } |
502 | |
503 | |
504 | /*************************************************************************/ |
505 | /* */ |
506 | /* <Function> */ |
507 | /* tt_face_load_hdmx */ |
508 | /* */ |
509 | /* <Description> */ |
510 | /* Load the `hdmx' table into the face object. */ |
511 | /* */ |
512 | /* <Input> */ |
513 | /* face :: A handle to the target face object. */ |
514 | /* */ |
515 | /* stream :: A handle to the input stream. */ |
516 | /* */ |
517 | /* <Return> */ |
518 | /* FreeType error code. 0 means success. */ |
519 | /* */ |
520 | |
521 | FT_LOCAL_DEF( FT_Error ) |
522 | tt_face_load_hdmx( TT_Face face, |
523 | FT_Stream stream ) |
524 | { |
525 | FT_Error error; |
526 | FT_Memory memory = stream->memory; |
527 | FT_UInt nn, num_records; |
528 | FT_ULong table_size, record_size; |
529 | FT_Byte* p; |
530 | FT_Byte* limit; |
531 | |
532 | |
533 | /* this table is optional */ |
534 | error = face->goto_table( face, TTAG_hdmx, stream, &table_size ); |
535 | if ( error || table_size < 8 ) |
536 | return FT_Err_Ok; |
537 | |
538 | if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) ) |
539 | goto Exit; |
540 | |
541 | p = face->hdmx_table; |
542 | limit = p + table_size; |
543 | |
544 | /* Given that `hdmx' tables are losing its importance (for example, */ |
545 | /* variation fonts introduced in OpenType 1.8 must not have this */ |
546 | /* table) we no longer test for a correct `version' field. */ |
547 | p += 2; |
548 | num_records = FT_NEXT_USHORT( p ); |
549 | record_size = FT_NEXT_ULONG( p ); |
550 | |
551 | /* The maximum number of bytes in an hdmx device record is the */ |
552 | /* maximum number of glyphs + 2; this is 0xFFFF + 2, thus */ |
553 | /* explaining why `record_size' is a long (which we read as */ |
554 | /* unsigned long for convenience). In practice, two bytes are */ |
555 | /* sufficient to hold the size value. */ |
556 | /* */ |
557 | /* There are at least two fonts, HANNOM-A and HANNOM-B version */ |
558 | /* 2.0 (2005), which get this wrong: The upper two bytes of */ |
559 | /* the size value are set to 0xFF instead of 0x00. We catch */ |
560 | /* and fix this. */ |
561 | |
562 | if ( record_size >= 0xFFFF0000UL ) |
563 | record_size &= 0xFFFFU; |
564 | |
565 | /* The limit for `num_records' is a heuristic value. */ |
566 | if ( num_records > 255 || |
567 | ( num_records > 0 && |
568 | ( record_size > 0x10001L || |
569 | record_size < 4 ) ) ) |
570 | { |
571 | error = FT_THROW( Invalid_File_Format ); |
572 | goto Fail; |
573 | } |
574 | |
575 | if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) ) |
576 | goto Fail; |
577 | |
578 | for ( nn = 0; nn < num_records; nn++ ) |
579 | { |
580 | if ( p + record_size > limit ) |
581 | break; |
582 | |
583 | face->hdmx_record_sizes[nn] = p[0]; |
584 | p += record_size; |
585 | } |
586 | |
587 | face->hdmx_record_count = nn; |
588 | face->hdmx_table_size = table_size; |
589 | face->hdmx_record_size = record_size; |
590 | |
591 | Exit: |
592 | return error; |
593 | |
594 | Fail: |
595 | FT_FRAME_RELEASE( face->hdmx_table ); |
596 | face->hdmx_table_size = 0; |
597 | goto Exit; |
598 | } |
599 | |
600 | |
601 | FT_LOCAL_DEF( void ) |
602 | tt_face_free_hdmx( TT_Face face ) |
603 | { |
604 | FT_Stream stream = face->root.stream; |
605 | FT_Memory memory = stream->memory; |
606 | |
607 | |
608 | FT_FREE( face->hdmx_record_sizes ); |
609 | FT_FRAME_RELEASE( face->hdmx_table ); |
610 | } |
611 | |
612 | |
613 | /*************************************************************************/ |
614 | /* */ |
615 | /* Return the advance width table for a given pixel size if it is found */ |
616 | /* in the font's `hdmx' table (if any). */ |
617 | /* */ |
618 | FT_LOCAL_DEF( FT_Byte* ) |
619 | tt_face_get_device_metrics( TT_Face face, |
620 | FT_UInt ppem, |
621 | FT_UInt gindex ) |
622 | { |
623 | FT_UInt nn; |
624 | FT_Byte* result = NULL; |
625 | FT_ULong record_size = face->hdmx_record_size; |
626 | FT_Byte* record = face->hdmx_table + 8; |
627 | |
628 | |
629 | for ( nn = 0; nn < face->hdmx_record_count; nn++ ) |
630 | if ( face->hdmx_record_sizes[nn] == ppem ) |
631 | { |
632 | gindex += 2; |
633 | if ( gindex < record_size ) |
634 | result = record + nn * record_size + gindex; |
635 | break; |
636 | } |
637 | |
638 | return result; |
639 | } |
640 | |
641 | |
642 | /* END */ |
643 | |