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