]>
Commit | Line | Data |
---|---|---|
1 | /***************************************************************************/ | |
2 | /* */ | |
3 | /* t2load.c */ | |
4 | /* */ | |
5 | /* TrueType glyph data/program tables loader (body). */ | |
6 | /* */ | |
7 | /* Copyright 1996-2000 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 <freetype/internal/ftdebug.h> | |
20 | #include <freetype/internal/ftobjs.h> | |
21 | #include <freetype/internal/ftstream.h> | |
22 | #include <freetype/internal/psnames.h> | |
23 | ||
24 | #include <freetype/internal/t2errors.h> | |
25 | #include <freetype/tttags.h> | |
26 | ||
27 | ||
28 | #ifdef FT_FLAT_COMPILE | |
29 | ||
30 | #include "t2load.h" | |
31 | #include "t2parse.h" | |
32 | ||
33 | #else | |
34 | ||
35 | #include <cff/t2load.h> | |
36 | #include <cff/t2parse.h> | |
37 | ||
38 | #endif | |
39 | ||
40 | ||
41 | /*************************************************************************/ | |
42 | /* */ | |
43 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | |
44 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | |
45 | /* messages during execution. */ | |
46 | /* */ | |
47 | #undef FT_COMPONENT | |
48 | #define FT_COMPONENT trace_t2load | |
49 | ||
50 | ||
51 | /* read a CFF offset from memory */ | |
52 | static | |
53 | FT_ULong t2_get_offset( FT_Byte* p, | |
54 | FT_Byte off_size ) | |
55 | { | |
56 | FT_ULong result; | |
57 | ||
58 | ||
59 | for ( result = 0; off_size > 0; off_size-- ) | |
60 | { | |
61 | result <<= 8; | |
62 | result |= *p++; | |
63 | } | |
64 | ||
65 | return result; | |
66 | } | |
67 | ||
68 | ||
69 | static | |
70 | FT_Error t2_new_cff_index( CFF_Index* index, | |
71 | FT_Stream stream, | |
72 | FT_Bool load ) | |
73 | { | |
74 | FT_Error error; | |
75 | FT_Memory memory = stream->memory; | |
76 | FT_UShort count; | |
77 | ||
78 | ||
79 | MEM_Set( index, 0, sizeof ( *index ) ); | |
80 | ||
81 | index->stream = stream; | |
82 | if ( !READ_UShort( count ) && | |
83 | count > 0 ) | |
84 | { | |
85 | FT_Byte* p; | |
86 | FT_Byte offsize; | |
87 | FT_ULong data_size; | |
88 | FT_ULong* poff; | |
89 | ||
90 | ||
91 | /* there is at least one element; read the offset size, */ | |
92 | /* then access the offset table to compute the index's total size */ | |
93 | if ( READ_Byte( offsize ) ) | |
94 | goto Exit; | |
95 | ||
96 | index->stream = stream; | |
97 | index->count = count; | |
98 | index->off_size = offsize; | |
99 | data_size = (FT_ULong)( count + 1 ) * offsize; | |
100 | ||
101 | if ( ALLOC_ARRAY( index->offsets, count + 1, FT_ULong ) || | |
102 | ACCESS_Frame( data_size ) ) | |
103 | goto Exit; | |
104 | ||
105 | poff = index->offsets; | |
106 | p = (FT_Byte*)stream->cursor; | |
107 | ||
108 | for ( ; (FT_Short)count >= 0; count-- ) | |
109 | { | |
110 | poff[0] = t2_get_offset( p, offsize ); | |
111 | poff++; | |
112 | p += offsize; | |
113 | } | |
114 | ||
115 | FORGET_Frame(); | |
116 | ||
117 | index->data_offset = FILE_Pos(); | |
118 | data_size = poff[-1] - 1; | |
119 | ||
120 | if ( load ) | |
121 | { | |
122 | /* load the data */ | |
123 | if ( EXTRACT_Frame( data_size, index->bytes ) ) | |
124 | goto Exit; | |
125 | } | |
126 | else | |
127 | { | |
128 | /* skip the data */ | |
129 | (void)FILE_Skip( data_size ); | |
130 | } | |
131 | } | |
132 | ||
133 | Exit: | |
134 | if ( error ) | |
135 | FREE( index->offsets ); | |
136 | ||
137 | return error; | |
138 | } | |
139 | ||
140 | ||
141 | static | |
142 | void t2_done_cff_index( CFF_Index* index ) | |
143 | { | |
144 | if ( index->stream ) | |
145 | { | |
146 | FT_Stream stream = index->stream; | |
147 | FT_Memory memory = stream->memory; | |
148 | ||
149 | ||
150 | if ( index->bytes ) | |
151 | RELEASE_Frame( index->bytes ); | |
152 | ||
153 | FREE( index->offsets ); | |
154 | MEM_Set( index, 0, sizeof ( *index ) ); | |
155 | } | |
156 | } | |
157 | ||
158 | ||
159 | static | |
160 | FT_Error t2_explicit_cff_index( CFF_Index* index, | |
161 | FT_Byte*** table ) | |
162 | { | |
163 | FT_Error error = 0; | |
164 | FT_Memory memory = index->stream->memory; | |
165 | FT_UInt n, offset, old_offset; | |
166 | FT_Byte** t; | |
167 | ||
168 | ||
169 | *table = 0; | |
170 | ||
171 | if ( index->count > 0 && !ALLOC_ARRAY( t, index->count + 1, FT_Byte* ) ) | |
172 | { | |
173 | old_offset = 1; | |
174 | for ( n = 0; n <= index->count; n++ ) | |
175 | { | |
176 | offset = index->offsets[n]; | |
177 | if ( !offset ) | |
178 | offset = old_offset; | |
179 | ||
180 | t[n] = index->bytes + offset - 1; | |
181 | ||
182 | old_offset = offset; | |
183 | } | |
184 | *table = t; | |
185 | } | |
186 | ||
187 | return error; | |
188 | } | |
189 | ||
190 | ||
191 | LOCAL_FUNC | |
192 | FT_Error T2_Access_Element( CFF_Index* index, | |
193 | FT_UInt element, | |
194 | FT_Byte** pbytes, | |
195 | FT_ULong* pbyte_len ) | |
196 | { | |
197 | FT_Error error = 0; | |
198 | ||
199 | ||
200 | if ( index && index->count > element ) | |
201 | { | |
202 | /* compute start and end offsets */ | |
203 | FT_ULong off1, off2; | |
204 | ||
205 | ||
206 | off1 = index->offsets[element]; | |
207 | if ( off1 ) | |
208 | { | |
209 | do | |
210 | { | |
211 | element++; | |
212 | off2 = index->offsets[element]; | |
213 | ||
214 | } while ( off2 == 0 && element < index->count ); | |
215 | ||
216 | if ( !off2 ) | |
217 | off1 = 0; | |
218 | } | |
219 | ||
220 | /* access element */ | |
221 | if ( off1 ) | |
222 | { | |
223 | *pbyte_len = off2 - off1; | |
224 | ||
225 | if ( index->bytes ) | |
226 | { | |
227 | /* this index was completely loaded in memory, that's easy */ | |
228 | *pbytes = index->bytes + off1 - 1; | |
229 | } | |
230 | else | |
231 | { | |
232 | /* this index is still on disk/file, access it through a frame */ | |
233 | FT_Stream stream = index->stream; | |
234 | ||
235 | ||
236 | if ( FILE_Seek( index->data_offset + off1 - 1 ) || | |
237 | EXTRACT_Frame( off2 - off1, *pbytes ) ) | |
238 | goto Exit; | |
239 | } | |
240 | } | |
241 | else | |
242 | { | |
243 | /* empty index element */ | |
244 | *pbytes = 0; | |
245 | *pbyte_len = 0; | |
246 | } | |
247 | } | |
248 | else | |
249 | error = T2_Err_Invalid_Argument; | |
250 | ||
251 | Exit: | |
252 | return error; | |
253 | } | |
254 | ||
255 | ||
256 | LOCAL_FUNC | |
257 | void T2_Forget_Element( CFF_Index* index, | |
258 | FT_Byte** pbytes ) | |
259 | { | |
260 | if ( index->bytes == 0 ) | |
261 | { | |
262 | FT_Stream stream = index->stream; | |
263 | ||
264 | ||
265 | RELEASE_Frame( *pbytes ); | |
266 | } | |
267 | } | |
268 | ||
269 | ||
270 | LOCAL_FUNC | |
271 | FT_String* T2_Get_Name( CFF_Index* index, | |
272 | FT_UInt element ) | |
273 | { | |
274 | FT_Memory memory = index->stream->memory; | |
275 | FT_Byte* bytes; | |
276 | FT_ULong byte_len; | |
277 | FT_Error error; | |
278 | FT_String* name = 0; | |
279 | ||
280 | ||
281 | error = T2_Access_Element( index, element, &bytes, &byte_len ); | |
282 | if ( error ) | |
283 | goto Exit; | |
284 | ||
285 | if ( !ALLOC( name, byte_len + 1 ) ) | |
286 | { | |
287 | MEM_Copy( name, bytes, byte_len ); | |
288 | name[byte_len] = 0; | |
289 | } | |
290 | T2_Forget_Element( index, &bytes ); | |
291 | ||
292 | Exit: | |
293 | return name; | |
294 | } | |
295 | ||
296 | ||
297 | LOCAL_FUNC | |
298 | FT_String* T2_Get_String( CFF_Index* index, | |
299 | FT_UInt sid, | |
300 | PSNames_Interface* interface ) | |
301 | { | |
302 | /* if it is not a standard string, return it */ | |
303 | if ( sid > 390 ) | |
304 | return T2_Get_Name( index, sid - 390 ); | |
305 | ||
306 | /* that's a standard string, fetch a copy from the PSName module */ | |
307 | { | |
308 | FT_String* name = 0; | |
309 | const char* adobe_name = interface->adobe_std_strings( sid ); | |
310 | FT_UInt len; | |
311 | ||
312 | ||
313 | if ( adobe_name ) | |
314 | { | |
315 | FT_Memory memory = index->stream->memory; | |
316 | FT_Error error; | |
317 | ||
318 | ||
319 | len = (FT_UInt)strlen( adobe_name ); | |
320 | if ( !ALLOC( name, len + 1 ) ) | |
321 | { | |
322 | MEM_Copy( name, adobe_name, len ); | |
323 | name[len] = 0; | |
324 | } | |
325 | } | |
326 | ||
327 | return name; | |
328 | } | |
329 | } | |
330 | ||
331 | ||
332 | /*************************************************************************/ | |
333 | /*************************************************************************/ | |
334 | /*** ***/ | |
335 | /*** FD Select table support ***/ | |
336 | /*** ***/ | |
337 | /*************************************************************************/ | |
338 | /*************************************************************************/ | |
339 | ||
340 | ||
341 | static | |
342 | void CFF_Done_FD_Select( CFF_FD_Select* select, | |
343 | FT_Stream stream ) | |
344 | { | |
345 | if ( select->data ) | |
346 | RELEASE_Frame( select->data ); | |
347 | ||
348 | select->data_size = 0; | |
349 | select->format = 0; | |
350 | select->range_count = 0; | |
351 | } | |
352 | ||
353 | ||
354 | static | |
355 | FT_Error CFF_Load_FD_Select( CFF_FD_Select* select, | |
356 | FT_UInt num_glyphs, | |
357 | FT_Stream stream, | |
358 | FT_ULong offset ) | |
359 | { | |
360 | FT_Error error; | |
361 | FT_Byte format; | |
362 | FT_UInt num_ranges; | |
363 | ||
364 | ||
365 | /* read format */ | |
366 | if ( FILE_Seek( offset ) || READ_Byte( format ) ) | |
367 | goto Exit; | |
368 | ||
369 | select->format = format; | |
370 | select->cache_count = 0; /* clear cache */ | |
371 | ||
372 | switch ( format ) | |
373 | { | |
374 | case 0: /* format 0, that's simple */ | |
375 | select->data_size = num_glyphs; | |
376 | goto Load_Data; | |
377 | ||
378 | case 3: /* format 3, a tad more complex */ | |
379 | if ( READ_UShort( num_ranges ) ) | |
380 | goto Exit; | |
381 | ||
382 | select->data_size = num_ranges * 3 + 2; | |
383 | ||
384 | Load_Data: | |
385 | if ( EXTRACT_Frame( select->data_size, select->data ) ) | |
386 | goto Exit; | |
387 | break; | |
388 | ||
389 | default: /* hmm... that's wrong */ | |
390 | error = T2_Err_Invalid_File_Format; | |
391 | } | |
392 | ||
393 | Exit: | |
394 | return error; | |
395 | } | |
396 | ||
397 | ||
398 | LOCAL_FUNC | |
399 | FT_Byte CFF_Get_FD( CFF_FD_Select* select, | |
400 | FT_UInt glyph_index ) | |
401 | { | |
402 | FT_Byte fd = 0; | |
403 | ||
404 | ||
405 | switch ( select->format ) | |
406 | { | |
407 | case 0: | |
408 | fd = select->data[glyph_index]; | |
409 | break; | |
410 | ||
411 | case 3: | |
412 | /* first, compare to cache */ | |
413 | if ( (FT_UInt)(glyph_index-select->cache_first) < select->cache_count ) | |
414 | { | |
415 | fd = select->cache_fd; | |
416 | break; | |
417 | } | |
418 | ||
419 | /* then, lookup the ranges array */ | |
420 | { | |
421 | FT_Byte* p = select->data; | |
422 | FT_Byte* p_limit = p + select->data_size; | |
423 | FT_Byte fd2; | |
424 | FT_UInt first, limit; | |
425 | ||
426 | ||
427 | first = NEXT_UShort( p ); | |
428 | do | |
429 | { | |
430 | if ( glyph_index < first ) | |
431 | break; | |
432 | ||
433 | fd2 = *p++; | |
434 | limit = NEXT_UShort( p ); | |
435 | ||
436 | if ( glyph_index < limit ) | |
437 | { | |
438 | fd = fd2; | |
439 | ||
440 | /* update cache */ | |
441 | select->cache_first = first; | |
442 | select->cache_count = limit-first; | |
443 | select->cache_fd = fd2; | |
444 | break; | |
445 | } | |
446 | first = limit; | |
447 | ||
448 | } while ( p < p_limit ); | |
449 | } | |
450 | break; | |
451 | ||
452 | default: | |
453 | ; | |
454 | } | |
455 | ||
456 | return fd; | |
457 | } | |
458 | ||
459 | ||
460 | /*************************************************************************/ | |
461 | /*************************************************************************/ | |
462 | /*** ***/ | |
463 | /*** CFF font support ***/ | |
464 | /*** ***/ | |
465 | /*************************************************************************/ | |
466 | /*************************************************************************/ | |
467 | ||
468 | ||
469 | static | |
470 | FT_Error CFF_Load_SubFont( CFF_SubFont* font, | |
471 | CFF_Index* index, | |
472 | FT_UInt font_index, | |
473 | FT_Stream stream, | |
474 | FT_ULong base_offset ) | |
475 | { | |
476 | FT_Error error; | |
477 | T2_Parser parser; | |
478 | FT_Byte* dict; | |
479 | FT_ULong dict_len; | |
480 | CFF_Font_Dict* top = &font->font_dict; | |
481 | CFF_Private* priv = &font->private_dict; | |
482 | ||
483 | ||
484 | T2_Parser_Init( &parser, T2CODE_TOPDICT, &font->font_dict ); | |
485 | ||
486 | /* set defaults */ | |
487 | MEM_Set( top, 0, sizeof ( *top ) ); | |
488 | ||
489 | top->underline_position = -100; | |
490 | top->underline_thickness = 50; | |
491 | top->charstring_type = 2; | |
492 | top->font_matrix.xx = 0x10000L; | |
493 | top->font_matrix.yy = 0x10000L; | |
494 | top->cid_count = 8720; | |
495 | ||
496 | error = T2_Access_Element( index, font_index, &dict, &dict_len ) || | |
497 | T2_Parser_Run( &parser, dict, dict + dict_len ); | |
498 | ||
499 | T2_Forget_Element( index, &dict ); | |
500 | ||
501 | if ( error ) | |
502 | goto Exit; | |
503 | ||
504 | /* if it is a CID font, we stop there */ | |
505 | if ( top->cid_registry ) | |
506 | goto Exit; | |
507 | ||
508 | /* parse the private dictionary, if any */ | |
509 | if ( top->private_offset && top->private_size ) | |
510 | { | |
511 | /* set defaults */ | |
512 | MEM_Set( priv, 0, sizeof ( *priv ) ); | |
513 | ||
514 | priv->blue_shift = 7; | |
515 | priv->blue_fuzz = 1; | |
516 | priv->lenIV = -1; | |
517 | priv->expansion_factor = (FT_Fixed)0.06 * 0x10000L; | |
518 | priv->blue_scale = (FT_Fixed)0.039625 * 0x10000L; | |
519 | ||
520 | T2_Parser_Init( &parser, T2CODE_PRIVATE, priv ); | |
521 | ||
522 | if ( FILE_Seek( base_offset + font->font_dict.private_offset ) || | |
523 | ACCESS_Frame( font->font_dict.private_size ) ) | |
524 | goto Exit; | |
525 | ||
526 | error = T2_Parser_Run( &parser, | |
527 | (FT_Byte*)stream->cursor, | |
528 | (FT_Byte*)stream->limit ); | |
529 | FORGET_Frame(); | |
530 | if ( error ) | |
531 | goto Exit; | |
532 | } | |
533 | ||
534 | /* read the local subrs, if any */ | |
535 | if ( priv->local_subrs_offset ) | |
536 | { | |
537 | if ( FILE_Seek( base_offset + top->private_offset + | |
538 | priv->local_subrs_offset ) ) | |
539 | goto Exit; | |
540 | ||
541 | error = t2_new_cff_index( &font->local_subrs_index, stream, 1 ); | |
542 | if ( error ) | |
543 | goto Exit; | |
544 | ||
545 | font->num_local_subrs = font->local_subrs_index.count; | |
546 | error = t2_explicit_cff_index( &font->local_subrs_index, | |
547 | &font->local_subrs ); | |
548 | } | |
549 | ||
550 | Exit: | |
551 | return error; | |
552 | } | |
553 | ||
554 | ||
555 | static | |
556 | void CFF_Done_SubFont( FT_Memory memory, | |
557 | CFF_SubFont* subfont ) | |
558 | { | |
559 | if ( subfont ) | |
560 | { | |
561 | t2_done_cff_index( &subfont->local_subrs_index ); | |
562 | FREE( subfont->local_subrs ); | |
563 | } | |
564 | } | |
565 | ||
566 | ||
567 | LOCAL_FUNC | |
568 | FT_Error T2_Load_CFF_Font( FT_Stream stream, | |
569 | FT_Int face_index, | |
570 | CFF_Font* font ) | |
571 | { | |
572 | static const FT_Frame_Field cff_header_fields[] = | |
573 | { | |
574 | FT_FRAME_START( 4 ), | |
575 | FT_FRAME_BYTE( CFF_Font, version_major ), | |
576 | FT_FRAME_BYTE( CFF_Font, version_minor ), | |
577 | FT_FRAME_BYTE( CFF_Font, header_size ), | |
578 | FT_FRAME_BYTE( CFF_Font, absolute_offsize ), | |
579 | FT_FRAME_END | |
580 | }; | |
581 | ||
582 | FT_Error error; | |
583 | FT_Memory memory = stream->memory; | |
584 | FT_ULong base_offset; | |
585 | CFF_Font_Dict* dict; | |
586 | ||
587 | ||
588 | MEM_Set( font, 0, sizeof ( *font ) ); | |
589 | font->stream = stream; | |
590 | font->memory = memory; | |
591 | dict = &font->top_font.font_dict; | |
592 | base_offset = FILE_Pos(); | |
593 | ||
594 | /* read CFF font header */ | |
595 | if ( READ_Fields( cff_header_fields, font ) ) | |
596 | goto Exit; | |
597 | ||
598 | /* check format */ | |
599 | if ( font->version_major != 1 || | |
600 | font->header_size < 4 || | |
601 | font->absolute_offsize > 4 ) | |
602 | { | |
603 | FT_TRACE2(( "[not a CFF font header!]\n" )); | |
604 | error = FT_Err_Unknown_File_Format; | |
605 | goto Exit; | |
606 | } | |
607 | ||
608 | /* skip the rest of the header */ | |
609 | (void)FILE_Skip( font->header_size - 4 ); | |
610 | ||
611 | /* read the name, top dict, string and global subrs index */ | |
612 | error = t2_new_cff_index( &font->name_index, stream, 0 ) || | |
613 | t2_new_cff_index( &font->font_dict_index, stream, 0 ) || | |
614 | t2_new_cff_index( &font->string_index, stream, 0 ) || | |
615 | t2_new_cff_index( &font->global_subrs_index, stream, 1 ); | |
616 | if ( error ) | |
617 | goto Exit; | |
618 | ||
619 | /* well, we don't really forget the `disabled' fonts... */ | |
620 | font->num_faces = font->name_index.count; | |
621 | if ( face_index >= (FT_Int)font->num_faces ) | |
622 | { | |
623 | FT_ERROR(( "T2_Load_CFF_Font: incorrect face index = %d\n", | |
624 | face_index )); | |
625 | error = T2_Err_Invalid_Argument; | |
626 | } | |
627 | ||
628 | /* in case of a font format check, simply exit now */ | |
629 | if ( face_index < 0 ) | |
630 | goto Exit; | |
631 | ||
632 | /* now, parse the top-level font dictionary */ | |
633 | error = CFF_Load_SubFont( &font->top_font, | |
634 | &font->font_dict_index, | |
635 | face_index, | |
636 | stream, | |
637 | base_offset ); | |
638 | if ( error ) | |
639 | goto Exit; | |
640 | ||
641 | /* now, check for a CID font */ | |
642 | if ( dict->cid_registry ) | |
643 | { | |
644 | CFF_Index fd_index; | |
645 | CFF_SubFont* sub; | |
646 | FT_UInt index; | |
647 | ||
648 | ||
649 | /* this is a CID-keyed font, we must now allocate a table of */ | |
650 | /* sub-fonts, then load each of them separately */ | |
651 | if ( FILE_Seek( base_offset + dict->cid_fd_array_offset ) ) | |
652 | goto Exit; | |
653 | ||
654 | error = t2_new_cff_index( &fd_index, stream, 0 ); | |
655 | if ( error ) | |
656 | goto Exit; | |
657 | ||
658 | if ( fd_index.count > CFF_MAX_CID_FONTS ) | |
659 | { | |
660 | FT_ERROR(( "T2_Load_CFF_Font: FD array too large in CID font\n" )); | |
661 | goto Fail_CID; | |
662 | } | |
663 | ||
664 | /* allocate & read each font dict independently */ | |
665 | font->num_subfonts = fd_index.count; | |
666 | if ( ALLOC_ARRAY( sub, fd_index.count, CFF_SubFont ) ) | |
667 | goto Fail_CID; | |
668 | ||
669 | /* setup pointer table */ | |
670 | for ( index = 0; index < fd_index.count; index++ ) | |
671 | font->subfonts[index] = sub + index; | |
672 | ||
673 | /* now load each sub font independently */ | |
674 | for ( index = 0; index < fd_index.count; index++ ) | |
675 | { | |
676 | sub = font->subfonts[index]; | |
677 | error = CFF_Load_SubFont( sub, &fd_index, index, | |
678 | stream, base_offset ); | |
679 | if ( error ) | |
680 | goto Fail_CID; | |
681 | } | |
682 | ||
683 | /* now load the FD Select array */ | |
684 | error = CFF_Load_FD_Select( &font->fd_select, | |
685 | dict->cid_count, | |
686 | stream, | |
687 | base_offset + dict->cid_fd_select_offset ); | |
688 | ||
689 | Fail_CID: | |
690 | t2_done_cff_index( &fd_index ); | |
691 | ||
692 | if ( error ) | |
693 | goto Exit; | |
694 | } | |
695 | else | |
696 | font->num_subfonts = 0; | |
697 | ||
698 | /* read the charstrings index now */ | |
699 | if ( dict->charstrings_offset == 0 ) | |
700 | { | |
701 | FT_ERROR(( "T2_Load_CFF_Font: no charstrings offset!\n" )); | |
702 | error = FT_Err_Unknown_File_Format; | |
703 | goto Exit; | |
704 | } | |
705 | ||
706 | if ( FILE_Seek( base_offset + dict->charstrings_offset ) ) | |
707 | goto Exit; | |
708 | ||
709 | error = t2_new_cff_index( &font->charstrings_index, stream, 0 ); | |
710 | if ( error ) | |
711 | goto Exit; | |
712 | ||
713 | /* explicit the global subrs */ | |
714 | font->num_global_subrs = font->global_subrs_index.count; | |
715 | font->num_glyphs = font->charstrings_index.count; | |
716 | ||
717 | error = t2_explicit_cff_index( &font->global_subrs_index, | |
718 | &font->global_subrs ) ; | |
719 | ||
720 | if ( error ) | |
721 | goto Exit; | |
722 | ||
723 | /* get the font name */ | |
724 | font->font_name = T2_Get_Name( &font->name_index, face_index ); | |
725 | ||
726 | Exit: | |
727 | return error; | |
728 | } | |
729 | ||
730 | ||
731 | LOCAL_FUNC | |
732 | void T2_Done_CFF_Font( CFF_Font* font ) | |
733 | { | |
734 | FT_Memory memory = font->memory; | |
735 | FT_UInt index; | |
736 | ||
737 | ||
738 | t2_done_cff_index( &font->global_subrs_index ); | |
739 | t2_done_cff_index( &font->string_index ); | |
740 | t2_done_cff_index( &font->font_dict_index ); | |
741 | t2_done_cff_index( &font->name_index ); | |
742 | t2_done_cff_index( &font->charstrings_index ); | |
743 | ||
744 | /* release font dictionaries */ | |
745 | for ( index = 0; index < font->num_subfonts; index++ ) | |
746 | CFF_Done_SubFont( memory, font->subfonts[index] ); | |
747 | ||
748 | CFF_Done_SubFont( memory, &font->top_font ); | |
749 | ||
750 | CFF_Done_FD_Select( &font->fd_select, font->stream ); | |
751 | ||
752 | FREE( font->global_subrs ); | |
753 | FREE( font->font_name ); | |
754 | } | |
755 | ||
756 | ||
757 | /* END */ |