OLD | NEW |
| (Empty) |
1 /***************************************************************************/ | |
2 /* */ | |
3 /* ttpload.c */ | |
4 /* */ | |
5 /* TrueType-specific tables loader (body). */ | |
6 /* */ | |
7 /* Copyright 1996-2002, 2004-2013 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 "../../include/ft2build.h" | |
20 #include "../../include/freetype/internal/ftdebug.h" | |
21 #include "../../include/freetype/internal/ftobjs.h" | |
22 #include "../../include/freetype/internal/ftstream.h" | |
23 #include "../../include/freetype/tttags.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 face->glyf_len = 0; | |
77 else if ( error ) | |
78 goto Exit; | |
79 | |
80 FT_TRACE2(( "Locations " )); | |
81 error = face->goto_table( face, TTAG_loca, stream, &table_len ); | |
82 if ( error ) | |
83 { | |
84 error = FT_THROW( Locations_Missing ); | |
85 goto Exit; | |
86 } | |
87 | |
88 if ( face->header.Index_To_Loc_Format != 0 ) | |
89 { | |
90 shift = 2; | |
91 | |
92 if ( table_len >= 0x40000L ) | |
93 { | |
94 FT_TRACE2(( "table too large\n" )); | |
95 error = FT_THROW( Invalid_Table ); | |
96 goto Exit; | |
97 } | |
98 face->num_locations = table_len >> shift; | |
99 } | |
100 else | |
101 { | |
102 shift = 1; | |
103 | |
104 if ( table_len >= 0x20000L ) | |
105 { | |
106 FT_TRACE2(( "table too large\n" )); | |
107 error = FT_THROW( Invalid_Table ); | |
108 goto Exit; | |
109 } | |
110 face->num_locations = table_len >> shift; | |
111 } | |
112 /* | |
113 * Extract the frame. We don't need to decompress it since | |
114 * we are able to parse it directly. | |
115 */ | |
116 if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) ) | |
117 goto Exit; | |
118 | |
119 FT_TRACE2(( "loaded\n" )); | |
120 | |
121 Exit: | |
122 return error; | |
123 } | |
124 | |
125 | |
126 FT_LOCAL_DEF( FT_ULong ) | |
127 tt_face_get_location( TT_Face face, | |
128 FT_UInt gindex, | |
129 FT_UInt *asize ) | |
130 { | |
131 FT_ULong pos1 = 0, pos2 = 0; | |
132 FT_Byte* p = NULL; | |
133 | |
134 if (!face || gindex >= face->num_locations) | |
135 { | |
136 if (asize) | |
137 *asize = 0; | |
138 | |
139 return 0; | |
140 } | |
141 | |
142 if ( face->header.Index_To_Loc_Format != 0 ) | |
143 { | |
144 p = face->glyph_locations + gindex * 4; | |
145 pos1 = FT_NEXT_ULONG(p); | |
146 pos2 = pos1; | |
147 //p has been moved to next location in the previous FT_NEXT_ULONG. | |
148 if ( gindex < face->num_locations - 1 ) | |
149 pos2 = FT_NEXT_ULONG(p); | |
150 } | |
151 else | |
152 { | |
153 p = face->glyph_locations + gindex * 2; | |
154 pos1 = FT_NEXT_USHORT(p); | |
155 pos2 = pos1; | |
156 //p has been moved to next location in the previous FT_NEXT_USHORT. | |
157 if ( gindex < face->num_locations - 1 ) | |
158 pos2 = FT_NEXT_USHORT( p ); | |
159 | |
160 pos1 <<= 1; | |
161 pos2 <<= 1; | |
162 } | |
163 | |
164 /* Check broken location data */ | |
165 if ( pos1 > face->glyf_len ) | |
166 { | |
167 FT_TRACE1(( "tt_face_get_location:" | |
168 " too large offset=0x%08lx found for gid=0x%04lx," | |
169 " exceeding the end of glyf table (0x%08lx)\n", | |
170 pos1, gindex, face->glyf_len )); | |
171 *asize = 0; | |
172 return 0; | |
173 } | |
174 | |
175 if ( pos2 > face->glyf_len ) | |
176 { | |
177 FT_TRACE1(( "tt_face_get_location:" | |
178 " too large offset=0x%08lx found for gid=0x%04lx," | |
179 " truncate at the end of glyf table (0x%08lx)\n", | |
180 pos2, gindex + 1, face->glyf_len )); | |
181 pos2 = face->glyf_len; | |
182 } | |
183 | |
184 /* The `loca' table must be ordered; it refers to the length of */ | |
185 /* an entry as the difference between the current and the next */ | |
186 /* position. However, there do exist (malformed) fonts which */ | |
187 /* don't obey this rule, so we are only able to provide an */ | |
188 /* upper bound for the size. */ | |
189 /* */ | |
190 /* We get (intentionally) a wrong, non-zero result in case the */ | |
191 /* `glyf' table is missing. */ | |
192 if ( pos2 >= pos1 ) | |
193 *asize = (FT_UInt)( pos2 - pos1 ); | |
194 else | |
195 *asize = (FT_UInt)( face->glyf_len - pos1 ); | |
196 | |
197 return pos1; | |
198 } | |
199 | |
200 | |
201 FT_LOCAL_DEF( void ) | |
202 tt_face_done_loca( TT_Face face ) | |
203 { | |
204 FT_Stream stream = face->root.stream; | |
205 | |
206 | |
207 FT_FRAME_RELEASE( face->glyph_locations ); | |
208 face->num_locations = 0; | |
209 } | |
210 | |
211 | |
212 | |
213 /*************************************************************************/ | |
214 /* */ | |
215 /* <Function> */ | |
216 /* tt_face_load_cvt */ | |
217 /* */ | |
218 /* <Description> */ | |
219 /* Load the control value table into a face object. */ | |
220 /* */ | |
221 /* <InOut> */ | |
222 /* face :: A handle to the target face object. */ | |
223 /* */ | |
224 /* <Input> */ | |
225 /* stream :: A handle to the input stream. */ | |
226 /* */ | |
227 /* <Return> */ | |
228 /* FreeType error code. 0 means success. */ | |
229 /* */ | |
230 FT_LOCAL_DEF( FT_Error ) | |
231 tt_face_load_cvt( TT_Face face, | |
232 FT_Stream stream ) | |
233 { | |
234 #ifdef TT_USE_BYTECODE_INTERPRETER | |
235 | |
236 FT_Error error; | |
237 FT_Memory memory = stream->memory; | |
238 FT_ULong table_len; | |
239 | |
240 | |
241 FT_TRACE2(( "CVT " )); | |
242 | |
243 error = face->goto_table( face, TTAG_cvt, stream, &table_len ); | |
244 if ( error ) | |
245 { | |
246 FT_TRACE2(( "is missing\n" )); | |
247 | |
248 face->cvt_size = 0; | |
249 face->cvt = NULL; | |
250 error = FT_Err_Ok; | |
251 | |
252 goto Exit; | |
253 } | |
254 | |
255 face->cvt_size = table_len / 2; | |
256 | |
257 if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) ) | |
258 goto Exit; | |
259 | |
260 if ( FT_FRAME_ENTER( face->cvt_size * 2L ) ) | |
261 goto Exit; | |
262 | |
263 { | |
264 FT_Short* cur = face->cvt; | |
265 FT_Short* limit = cur + face->cvt_size; | |
266 | |
267 | |
268 for ( ; cur < limit; cur++ ) | |
269 *cur = FT_GET_SHORT(); | |
270 } | |
271 | |
272 FT_FRAME_EXIT(); | |
273 FT_TRACE2(( "loaded\n" )); | |
274 | |
275 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT | |
276 if ( face->doblend ) | |
277 error = tt_face_vary_cvt( face, stream ); | |
278 #endif | |
279 | |
280 Exit: | |
281 return error; | |
282 | |
283 #else /* !TT_USE_BYTECODE_INTERPRETER */ | |
284 | |
285 FT_UNUSED( face ); | |
286 FT_UNUSED( stream ); | |
287 | |
288 return FT_Err_Ok; | |
289 | |
290 #endif | |
291 } | |
292 | |
293 | |
294 /*************************************************************************/ | |
295 /* */ | |
296 /* <Function> */ | |
297 /* tt_face_load_fpgm */ | |
298 /* */ | |
299 /* <Description> */ | |
300 /* Load the font program. */ | |
301 /* */ | |
302 /* <InOut> */ | |
303 /* face :: A handle to the target face object. */ | |
304 /* */ | |
305 /* <Input> */ | |
306 /* stream :: A handle to the input stream. */ | |
307 /* */ | |
308 /* <Return> */ | |
309 /* FreeType error code. 0 means success. */ | |
310 /* */ | |
311 FT_LOCAL_DEF( FT_Error ) | |
312 tt_face_load_fpgm( TT_Face face, | |
313 FT_Stream stream ) | |
314 { | |
315 #ifdef TT_USE_BYTECODE_INTERPRETER | |
316 | |
317 FT_Error error; | |
318 FT_ULong table_len; | |
319 | |
320 | |
321 FT_TRACE2(( "Font program " )); | |
322 | |
323 /* The font program is optional */ | |
324 error = face->goto_table( face, TTAG_fpgm, stream, &table_len ); | |
325 if ( error ) | |
326 { | |
327 face->font_program = NULL; | |
328 face->font_program_size = 0; | |
329 error = FT_Err_Ok; | |
330 | |
331 FT_TRACE2(( "is missing\n" )); | |
332 } | |
333 else | |
334 { | |
335 face->font_program_size = table_len; | |
336 if ( FT_FRAME_EXTRACT( table_len, face->font_program ) ) | |
337 goto Exit; | |
338 | |
339 FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size )); | |
340 } | |
341 | |
342 Exit: | |
343 return error; | |
344 | |
345 #else /* !TT_USE_BYTECODE_INTERPRETER */ | |
346 | |
347 FT_UNUSED( face ); | |
348 FT_UNUSED( stream ); | |
349 | |
350 return FT_Err_Ok; | |
351 | |
352 #endif | |
353 } | |
354 | |
355 | |
356 /*************************************************************************/ | |
357 /* */ | |
358 /* <Function> */ | |
359 /* tt_face_load_prep */ | |
360 /* */ | |
361 /* <Description> */ | |
362 /* Load the cvt program. */ | |
363 /* */ | |
364 /* <InOut> */ | |
365 /* face :: A handle to the target face object. */ | |
366 /* */ | |
367 /* <Input> */ | |
368 /* stream :: A handle to the input stream. */ | |
369 /* */ | |
370 /* <Return> */ | |
371 /* FreeType error code. 0 means success. */ | |
372 /* */ | |
373 FT_LOCAL_DEF( FT_Error ) | |
374 tt_face_load_prep( TT_Face face, | |
375 FT_Stream stream ) | |
376 { | |
377 #ifdef TT_USE_BYTECODE_INTERPRETER | |
378 | |
379 FT_Error error; | |
380 FT_ULong table_len; | |
381 | |
382 | |
383 FT_TRACE2(( "Prep program " )); | |
384 | |
385 error = face->goto_table( face, TTAG_prep, stream, &table_len ); | |
386 if ( error ) | |
387 { | |
388 face->cvt_program = NULL; | |
389 face->cvt_program_size = 0; | |
390 error = FT_Err_Ok; | |
391 | |
392 FT_TRACE2(( "is missing\n" )); | |
393 } | |
394 else | |
395 { | |
396 face->cvt_program_size = table_len; | |
397 if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) ) | |
398 goto Exit; | |
399 | |
400 FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size )); | |
401 } | |
402 | |
403 Exit: | |
404 return error; | |
405 | |
406 #else /* !TT_USE_BYTECODE_INTERPRETER */ | |
407 | |
408 FT_UNUSED( face ); | |
409 FT_UNUSED( stream ); | |
410 | |
411 return FT_Err_Ok; | |
412 | |
413 #endif | |
414 } | |
415 | |
416 | |
417 /*************************************************************************/ | |
418 /* */ | |
419 /* <Function> */ | |
420 /* tt_face_load_hdmx */ | |
421 /* */ | |
422 /* <Description> */ | |
423 /* Load the `hdmx' table into the face object. */ | |
424 /* */ | |
425 /* <Input> */ | |
426 /* face :: A handle to the target face object. */ | |
427 /* */ | |
428 /* stream :: A handle to the input stream. */ | |
429 /* */ | |
430 /* <Return> */ | |
431 /* FreeType error code. 0 means success. */ | |
432 /* */ | |
433 | |
434 FT_LOCAL_DEF( FT_Error ) | |
435 tt_face_load_hdmx( TT_Face face, | |
436 FT_Stream stream ) | |
437 { | |
438 FT_Error error; | |
439 FT_Memory memory = stream->memory; | |
440 FT_UInt version, nn, num_records; | |
441 FT_ULong table_size, record_size; | |
442 FT_Byte* p; | |
443 FT_Byte* limit; | |
444 | |
445 | |
446 /* this table is optional */ | |
447 error = face->goto_table( face, TTAG_hdmx, stream, &table_size ); | |
448 if ( error || table_size < 8 ) | |
449 return FT_Err_Ok; | |
450 | |
451 if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) ) | |
452 goto Exit; | |
453 | |
454 p = face->hdmx_table; | |
455 limit = p + table_size; | |
456 | |
457 version = FT_NEXT_USHORT( p ); | |
458 num_records = FT_NEXT_USHORT( p ); | |
459 record_size = FT_NEXT_ULONG( p ); | |
460 | |
461 /* The maximum number of bytes in an hdmx device record is the */ | |
462 /* maximum number of glyphs + 2; this is 0xFFFF + 2; this is */ | |
463 /* the reason why `record_size' is a long (which we read as */ | |
464 /* unsigned long for convenience). In practice, two bytes */ | |
465 /* sufficient to hold the size value. */ | |
466 /* */ | |
467 /* There are at least two fonts, HANNOM-A and HANNOM-B version */ | |
468 /* 2.0 (2005), which get this wrong: The upper two bytes of */ | |
469 /* the size value are set to 0xFF instead of 0x00. We catch */ | |
470 /* and fix this. */ | |
471 | |
472 if ( record_size >= 0xFFFF0000UL ) | |
473 record_size &= 0xFFFFU; | |
474 | |
475 /* The limit for `num_records' is a heuristic value. */ | |
476 | |
477 if ( version != 0 || num_records > 255 || record_size > 0x10001L ) | |
478 { | |
479 error = FT_THROW( Invalid_File_Format ); | |
480 goto Fail; | |
481 } | |
482 | |
483 if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) ) | |
484 goto Fail; | |
485 | |
486 for ( nn = 0; nn < num_records; nn++ ) | |
487 { | |
488 if ( p + record_size > limit ) | |
489 break; | |
490 | |
491 face->hdmx_record_sizes[nn] = p[0]; | |
492 p += record_size; | |
493 } | |
494 | |
495 face->hdmx_record_count = nn; | |
496 face->hdmx_table_size = table_size; | |
497 face->hdmx_record_size = record_size; | |
498 | |
499 Exit: | |
500 return error; | |
501 | |
502 Fail: | |
503 FT_FRAME_RELEASE( face->hdmx_table ); | |
504 face->hdmx_table_size = 0; | |
505 goto Exit; | |
506 } | |
507 | |
508 | |
509 FT_LOCAL_DEF( void ) | |
510 tt_face_free_hdmx( TT_Face face ) | |
511 { | |
512 FT_Stream stream = face->root.stream; | |
513 FT_Memory memory = stream->memory; | |
514 | |
515 | |
516 FT_FREE( face->hdmx_record_sizes ); | |
517 FT_FRAME_RELEASE( face->hdmx_table ); | |
518 } | |
519 | |
520 | |
521 /*************************************************************************/ | |
522 /* */ | |
523 /* Return the advance width table for a given pixel size if it is found */ | |
524 /* in the font's `hdmx' table (if any). */ | |
525 /* */ | |
526 FT_LOCAL_DEF( FT_Byte* ) | |
527 tt_face_get_device_metrics( TT_Face face, | |
528 FT_UInt ppem, | |
529 FT_UInt gindex ) | |
530 { | |
531 FT_UInt nn; | |
532 FT_Byte* result = NULL; | |
533 FT_ULong record_size = face->hdmx_record_size; | |
534 FT_Byte* record = face->hdmx_table + 8; | |
535 | |
536 | |
537 for ( nn = 0; nn < face->hdmx_record_count; nn++ ) | |
538 if ( face->hdmx_record_sizes[nn] == ppem ) | |
539 { | |
540 gindex += 2; | |
541 if ( gindex < record_size ) | |
542 result = record + nn * record_size + gindex; | |
543 break; | |
544 } | |
545 | |
546 return result; | |
547 } | |
548 | |
549 | |
550 /* END */ | |
OLD | NEW |