]>
Commit | Line | Data |
---|---|---|
cabec872 RR |
1 | /***************************************************************************/ |
2 | /* */ | |
3 | /* t2objs.c */ | |
4 | /* */ | |
5 | /* OpenType objects manager (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/ftcalc.h> | |
21 | #include <freetype/internal/ftstream.h> | |
22 | #include <freetype/fterrors.h> | |
23 | #include <freetype/ttnameid.h> | |
24 | #include <freetype/tttags.h> | |
25 | ||
26 | #include <freetype/internal/sfnt.h> | |
27 | #include <freetype/internal/psnames.h> | |
28 | ||
29 | ||
30 | #ifdef FT_FLAT_COMPILE | |
31 | ||
32 | #include "t2objs.h" | |
33 | #include "t2load.h" | |
34 | ||
35 | #else | |
36 | ||
37 | #include <cff/t2objs.h> | |
38 | #include <cff/t2load.h> | |
39 | ||
40 | #endif | |
41 | ||
42 | ||
43 | #include <freetype/internal/t2errors.h> | |
44 | ||
45 | #include <string.h> /* for strlen() */ | |
46 | ||
47 | ||
48 | /*************************************************************************/ | |
49 | /* */ | |
50 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | |
51 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | |
52 | /* messages during execution. */ | |
53 | /* */ | |
54 | #undef FT_COMPONENT | |
55 | #define FT_COMPONENT trace_t2objs | |
56 | ||
57 | ||
58 | /*************************************************************************/ | |
59 | /* */ | |
60 | /* FACE FUNCTIONS */ | |
61 | /* */ | |
62 | /*************************************************************************/ | |
63 | ||
64 | static | |
65 | FT_String* T2_StrCopy( FT_Memory memory, | |
66 | const FT_String* source ) | |
67 | { | |
68 | FT_Error error; | |
69 | FT_String* result = 0; | |
70 | FT_Int len = (FT_Int)strlen( source ); | |
71 | ||
72 | ||
73 | if ( !ALLOC( result, len + 1 ) ) | |
74 | { | |
75 | MEM_Copy( result, source, len ); | |
76 | result[len] = 0; | |
77 | } | |
78 | return result; | |
79 | } | |
80 | ||
81 | ||
82 | #if 0 | |
83 | ||
84 | /* this function is used to build a Unicode charmap from the glyph names */ | |
85 | /* in a file */ | |
86 | static | |
87 | FT_Error CFF_Build_Unicode_Charmap( T2_Face face, | |
88 | FT_ULong base_offset, | |
89 | PSNames_Interface* psnames ) | |
90 | { | |
91 | CFF_Font* font = (CFF_Font*)face->extra.data; | |
92 | FT_Memory memory = FT_FACE_MEMORY(face); | |
93 | FT_UInt n, num_glyphs = face->root.num_glyphs; | |
94 | const char** glyph_names; | |
95 | FT_Error error; | |
96 | CFF_Font_Dict* dict = &font->top_font.font_dict; | |
97 | FT_ULong charset_offset; | |
98 | FT_Byte format; | |
99 | FT_Stream stream = face->root.stream; | |
100 | ||
101 | ||
102 | charset_offset = dict->charset_offset; | |
103 | if ( !charset_offset ) | |
104 | { | |
105 | FT_ERROR(( "CFF.Build_Unicode_Charmap: charset table is missing\n" )); | |
106 | error = T2_Err_Invalid_File_Format; | |
107 | goto Exit; | |
108 | } | |
109 | ||
110 | /* allocate the charmap */ | |
111 | if ( ALLOC( face->charmap, ... | |
112 | ||
113 | /* seek to charset table and allocate glyph names table */ | |
114 | if ( FILE_Seek( base_offset + charset_offset ) || | |
115 | ALLOC_ARRAY( glyph_names, num_glyphs, const char* ) ) | |
116 | goto Exit; | |
117 | ||
118 | /* now, read each glyph name and store it in the glyph name table */ | |
119 | if ( READ_Byte( format ) ) | |
120 | goto Fail; | |
121 | ||
122 | switch ( format ) | |
123 | { | |
124 | case 0: /* format 0 - one SID per glyph */ | |
125 | { | |
126 | const char** gname = glyph_names; | |
127 | const char** limit = gname + num_glyphs; | |
128 | ||
129 | if ( ACCESS_Frame( num_glyphs*2 ) ) | |
130 | goto Fail; | |
131 | ||
132 | for ( ; gname < limit; gname++ ) | |
133 | gname[0] = T2_Get_String( &font->string_index, | |
134 | GET_UShort(), | |
135 | psnames ); | |
136 | FORGET_Frame(); | |
137 | break; | |
138 | } | |
139 | ||
140 | case 1: /* format 1 - sequential ranges */ | |
141 | case 2: /* format 2 - sequential ranges with 16-bit counts */ | |
142 | { | |
143 | const char** gname = glyph_names; | |
144 | const char** limit = gname + num_glyphs; | |
145 | FT_UInt len = 3; | |
146 | ||
147 | if (format == 2) | |
148 | len++; | |
149 | ||
150 | while (gname < limit) | |
151 | { | |
152 | FT_UInt first; | |
153 | FT_UInt count; | |
154 | ||
155 | if ( ACCESS_Frame( len ) ) | |
156 | goto Fail; | |
157 | ||
158 | first = GET_UShort(); | |
159 | if (format == 3) | |
160 | count = GET_UShort(); | |
161 | else | |
162 | count = GET_Byte(); | |
163 | ||
164 | FORGET_Frame(); | |
165 | ||
166 | for ( ; count > 0; count-- ) | |
167 | { | |
168 | gname[0] = T2_Get_String( &font->string_index, | |
169 | first, | |
170 | psnames ); | |
171 | gname++; | |
172 | first++; | |
173 | } | |
174 | } | |
175 | break; | |
176 | } | |
177 | ||
178 | default: /* unknown charset format! */ | |
179 | FT_ERROR(( "CFF: unknown charset format!\n" )); | |
180 | error = T2_Err_Invalid_File_Format; | |
181 | goto Fail; | |
182 | } | |
183 | ||
184 | /* all right, the glyph names were loaded, we now need to create */ | |
185 | /* the corresponding unicode charmap.. */ | |
186 | ||
187 | Fail: | |
188 | for ( n = 0; n < num_glyphs; n++ ) | |
189 | FREE( glyph_names[n] ); | |
190 | ||
191 | FREE( glyph_names ); | |
192 | ||
193 | Exit: | |
194 | return error; | |
195 | } | |
196 | ||
197 | #endif /* 0 */ | |
198 | ||
199 | ||
200 | static | |
201 | FT_Encoding find_encoding( int platform_id, | |
202 | int encoding_id ) | |
203 | { | |
204 | typedef struct TEncoding | |
205 | { | |
206 | int platform_id; | |
207 | int encoding_id; | |
208 | FT_Encoding encoding; | |
209 | ||
210 | } TEncoding; | |
211 | ||
212 | static | |
213 | const TEncoding tt_encodings[] = | |
214 | { | |
215 | { TT_PLATFORM_ISO, -1, ft_encoding_unicode }, | |
216 | ||
217 | { TT_PLATFORM_APPLE_UNICODE, -1, ft_encoding_unicode }, | |
218 | ||
219 | { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, ft_encoding_apple_roman }, | |
220 | ||
221 | { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, ft_encoding_unicode }, | |
222 | { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, ft_encoding_sjis }, | |
223 | { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, ft_encoding_gb2312 }, | |
224 | { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, ft_encoding_big5 }, | |
225 | { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, ft_encoding_wansung }, | |
226 | { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, ft_encoding_johab } | |
227 | }; | |
228 | ||
229 | const TEncoding *cur, *limit; | |
230 | ||
231 | ||
232 | cur = tt_encodings; | |
233 | limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] ); | |
234 | ||
235 | for ( ; cur < limit; cur++ ) | |
236 | { | |
237 | if ( cur->platform_id == platform_id ) | |
238 | { | |
239 | if ( cur->encoding_id == encoding_id || | |
240 | cur->encoding_id == -1 ) | |
241 | return cur->encoding; | |
242 | } | |
243 | } | |
244 | ||
245 | return ft_encoding_none; | |
246 | } | |
247 | ||
248 | ||
249 | /*************************************************************************/ | |
250 | /* */ | |
251 | /* <Function> */ | |
252 | /* T2_Init_Face */ | |
253 | /* */ | |
254 | /* <Description> */ | |
255 | /* Initializes a given OpenType face object. */ | |
256 | /* */ | |
257 | /* <Input> */ | |
258 | /* stream :: The source font stream. */ | |
259 | /* */ | |
260 | /* face_index :: The index of the font face in the resource. */ | |
261 | /* */ | |
262 | /* num_params :: Number of additional generic parameters. Ignored. */ | |
263 | /* */ | |
264 | /* params :: Additional generic parameters. Ignored. */ | |
265 | /* */ | |
266 | /* <InOut> */ | |
267 | /* face :: The newly built face object. */ | |
268 | /* */ | |
269 | /* <Return> */ | |
270 | /* FreeType error code. 0 means success. */ | |
271 | /* */ | |
272 | LOCAL_DEF | |
273 | FT_Error T2_Init_Face( FT_Stream stream, | |
274 | T2_Face face, | |
275 | FT_Int face_index, | |
276 | FT_Int num_params, | |
277 | FT_Parameter* params ) | |
278 | { | |
279 | FT_Error error; | |
280 | SFNT_Interface* sfnt; | |
281 | PSNames_Interface* psnames; | |
282 | FT_Bool pure_cff = 1; | |
283 | FT_Bool sfnt_format = 0; | |
284 | ||
285 | ||
286 | sfnt = (SFNT_Interface*)FT_Get_Module_Interface( | |
287 | face->root.driver->root.library, "sfnt" ); | |
288 | if ( !sfnt ) | |
289 | goto Bad_Format; | |
290 | ||
291 | psnames = (PSNames_Interface*)FT_Get_Module_Interface( | |
292 | face->root.driver->root.library, "psnames" ); | |
293 | ||
294 | /* create input stream from resource */ | |
295 | if ( FILE_Seek( 0 ) ) | |
296 | goto Exit; | |
297 | ||
298 | /* check that we have a valid OpenType file */ | |
299 | error = sfnt->init_face( stream, face, face_index, num_params, params ); | |
300 | if ( !error ) | |
301 | { | |
302 | if ( face->format_tag != 0x4F54544FL ) /* `OTTO'; OpenType/CFF font */ | |
303 | { | |
304 | FT_TRACE2(( "[not a valid OpenType/CFF font]\n" )); | |
305 | goto Bad_Format; | |
306 | } | |
307 | ||
308 | /* If we are performing a simple font format check, exit immediately */ | |
309 | if ( face_index < 0 ) | |
310 | return T2_Err_Ok; | |
311 | ||
312 | sfnt_format = 1; | |
313 | ||
314 | /* now, the font can be either an OpenType/CFF font, or a SVG CEF */ | |
315 | /* font in the later case; it doesn't have a `head' table */ | |
316 | error = face->goto_table( face, TTAG_head, stream, 0 ); | |
317 | if ( !error ) | |
318 | { | |
319 | pure_cff = 0; | |
320 | ||
321 | /* Load font directory */ | |
322 | error = sfnt->load_face( stream, face, | |
323 | face_index, num_params, params ); | |
324 | if ( error ) | |
325 | goto Exit; | |
326 | } | |
327 | else | |
328 | { | |
329 | /* load the `cmap' table by hand */ | |
330 | error = sfnt->load_charmaps( face, stream ); | |
331 | if ( error ) | |
332 | goto Exit; | |
333 | ||
334 | /* XXX: for now, we don't load the GPOS table, as OpenType Layout */ | |
335 | /* support will be added later to FreeType 2 as a separate module */ | |
336 | } | |
337 | ||
338 | /* now, load the CFF part of the file */ | |
339 | error = face->goto_table( face, TTAG_CFF, stream, 0 ); | |
340 | if ( error ) | |
341 | goto Exit; | |
342 | } | |
343 | else | |
344 | { | |
345 | /* rewind to start of file; we are going to load a pure-CFF font */ | |
346 | (void)FILE_Seek( 0 ); | |
347 | error = FT_Err_Ok; | |
348 | } | |
349 | ||
350 | /* now load and parse the CFF table in the file */ | |
351 | { | |
352 | CFF_Font* cff; | |
353 | FT_Memory memory = face->root.memory; | |
354 | FT_Face root; | |
355 | FT_UInt flags; | |
356 | FT_ULong base_offset; | |
357 | ||
358 | ||
359 | if ( ALLOC( cff, sizeof ( *cff ) ) ) | |
360 | goto Exit; | |
361 | ||
362 | base_offset = FILE_Pos(); | |
363 | ||
364 | face->extra.data = cff; | |
365 | error = T2_Load_CFF_Font( stream, face_index, cff ); | |
366 | if ( error ) | |
367 | goto Exit; | |
368 | ||
369 | /* Complement the root flags with some interesting information. */ | |
370 | /* Note that this is only necessary for pure CFF and CEF fonts */ | |
371 | ||
372 | root = &face->root; | |
373 | if ( pure_cff ) | |
374 | { | |
375 | CFF_Font_Dict* dict = &cff->top_font.font_dict; | |
376 | ||
377 | ||
378 | /* we need the `PSNames' module for pure-CFF and CEF formats */ | |
379 | if ( !psnames ) | |
380 | { | |
381 | FT_ERROR(( "T2_Init_Face:" )); | |
382 | FT_ERROR(( " cannot open CFF & CEF fonts\n" )); | |
383 | FT_ERROR(( " " )); | |
384 | FT_ERROR(( " without the `PSNames' module\n" )); | |
385 | goto Bad_Format; | |
386 | } | |
387 | ||
388 | /* compute number of glyphs */ | |
389 | if ( dict->cid_registry ) | |
390 | root->num_glyphs = dict->cid_count; | |
391 | else | |
392 | root->num_glyphs = cff->charstrings_index.count; | |
393 | ||
394 | /* set global bbox, as well as EM size */ | |
395 | root->units_per_EM = (FT_UInt)FT_DivFix( 1000L << 16, | |
396 | dict->font_matrix.yy ) >> 16; | |
397 | root->bbox = dict->font_bbox; | |
398 | root->ascender = (FT_Short)root->bbox.yMax; | |
399 | root->descender = (FT_Short)root->bbox.yMin; | |
400 | ||
401 | /* retrieve font family & style name */ | |
402 | root->family_name = T2_Get_Name( &cff->name_index, face_index ); | |
403 | if ( dict->cid_registry ) | |
404 | { | |
405 | root->style_name = T2_StrCopy( memory, "Regular" ); /* XXXX */ | |
406 | } | |
407 | else | |
408 | { | |
409 | root->style_name = T2_Get_String( &cff->string_index, | |
410 | dict->weight, | |
411 | psnames ); | |
412 | } | |
413 | ||
414 | /*******************************************************************/ | |
415 | /* */ | |
416 | /* Compute face flags. */ | |
417 | /* */ | |
418 | flags = FT_FACE_FLAG_SCALABLE | /* scalable outlines */ | |
419 | FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ | |
420 | ||
421 | if ( sfnt_format ) | |
422 | flags |= FT_FACE_FLAG_SFNT; | |
423 | ||
424 | /* fixed width font? */ | |
425 | if ( dict->is_fixed_pitch ) | |
426 | flags |= FT_FACE_FLAG_FIXED_WIDTH; | |
427 | ||
428 | /* XXXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */ | |
429 | #if 0 | |
430 | /* kerning available? */ | |
431 | if ( face->kern_pairs ) | |
432 | flags |= FT_FACE_FLAG_KERNING; | |
433 | #endif | |
434 | ||
435 | root->face_flags = flags; | |
436 | ||
437 | /*******************************************************************/ | |
438 | /* */ | |
439 | /* Compute style flags. */ | |
440 | /* */ | |
441 | flags = 0; | |
442 | ||
443 | if ( dict->italic_angle ) | |
444 | flags |= FT_STYLE_FLAG_ITALIC; | |
445 | ||
446 | /* XXX: may not be correct */ | |
447 | if ( cff->top_font.private_dict.force_bold ) | |
448 | flags |= FT_STYLE_FLAG_BOLD; | |
449 | ||
450 | root->style_flags = flags; | |
451 | ||
452 | /* set the charmaps if any */ | |
453 | if ( sfnt_format ) | |
454 | { | |
455 | /*****************************************************************/ | |
456 | /* */ | |
457 | /* Polish the charmaps. */ | |
458 | /* */ | |
459 | /* Try to set the charmap encoding according to the platform & */ | |
460 | /* encoding ID of each charmap. */ | |
461 | /* */ | |
462 | TT_CharMap charmap; | |
463 | FT_Int n; | |
464 | ||
465 | ||
466 | charmap = face->charmaps; | |
467 | root->num_charmaps = face->num_charmaps; | |
468 | ||
469 | /* allocate table of pointers */ | |
470 | if ( ALLOC_ARRAY( root->charmaps, root->num_charmaps, FT_CharMap ) ) | |
471 | goto Exit; | |
472 | ||
473 | for ( n = 0; n < root->num_charmaps; n++, charmap++ ) | |
474 | { | |
475 | FT_Int platform = charmap->cmap.platformID; | |
476 | FT_Int encoding = charmap->cmap.platformEncodingID; | |
477 | ||
478 | ||
479 | charmap->root.face = (FT_Face)face; | |
480 | charmap->root.platform_id = platform; | |
481 | charmap->root.encoding_id = encoding; | |
482 | charmap->root.encoding = find_encoding( platform, encoding ); | |
483 | ||
484 | /* now, set root->charmap with a unicode charmap */ | |
485 | /* wherever available */ | |
486 | if ( !root->charmap && | |
487 | charmap->root.encoding == ft_encoding_unicode ) | |
488 | root->charmap = (FT_CharMap)charmap; | |
489 | ||
490 | root->charmaps[n] = (FT_CharMap)charmap; | |
491 | } | |
492 | } | |
493 | } | |
494 | } | |
495 | ||
496 | Exit: | |
497 | return error; | |
498 | ||
499 | Bad_Format: | |
500 | error = FT_Err_Unknown_File_Format; | |
501 | goto Exit; | |
502 | } | |
503 | ||
504 | ||
505 | /*************************************************************************/ | |
506 | /* */ | |
507 | /* <Function> */ | |
508 | /* T2_Done_Face */ | |
509 | /* */ | |
510 | /* <Description> */ | |
511 | /* Finalizes a given face object. */ | |
512 | /* */ | |
513 | /* <Input> */ | |
514 | /* face :: A pointer to the face object to destroy. */ | |
515 | /* */ | |
516 | LOCAL_DEF | |
517 | void T2_Done_Face( T2_Face face ) | |
518 | { | |
519 | FT_Memory memory = face->root.memory; | |
520 | SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt; | |
521 | ||
522 | ||
523 | if ( sfnt ) | |
524 | sfnt->done_face( face ); | |
525 | ||
526 | { | |
527 | CFF_Font* cff = (CFF_Font*)face->extra.data; | |
528 | ||
529 | ||
530 | if ( cff ) | |
531 | { | |
532 | T2_Done_CFF_Font( cff ); | |
533 | FREE( face->extra.data ); | |
534 | } | |
535 | } | |
536 | } | |
537 | ||
538 | ||
539 | /*************************************************************************/ | |
540 | /* */ | |
541 | /* <Function> */ | |
542 | /* T2_Init_Driver */ | |
543 | /* */ | |
544 | /* <Description> */ | |
545 | /* Initializes a given OpenType driver object. */ | |
546 | /* */ | |
547 | /* <Input> */ | |
548 | /* driver :: A handle to the target driver object. */ | |
549 | /* */ | |
550 | /* <Return> */ | |
551 | /* FreeType error code. 0 means success. */ | |
552 | /* */ | |
553 | LOCAL_FUNC | |
554 | FT_Error T2_Init_Driver( T2_Driver driver ) | |
555 | { | |
556 | /* init extension registry if needed */ | |
557 | ||
558 | #ifdef TT_CONFIG_OPTION_EXTEND_ENGINE | |
559 | ||
560 | return TT_Init_Extensions( driver ); | |
561 | ||
562 | #else | |
563 | ||
564 | FT_UNUSED( driver ); | |
565 | ||
566 | return T2_Err_Ok; | |
567 | ||
568 | #endif | |
569 | } | |
570 | ||
571 | ||
572 | /*************************************************************************/ | |
573 | /* */ | |
574 | /* <Function> */ | |
575 | /* T2_Done_Driver */ | |
576 | /* */ | |
577 | /* <Description> */ | |
578 | /* Finalizes a given OpenType driver. */ | |
579 | /* */ | |
580 | /* <Input> */ | |
581 | /* driver :: A handle to the target OpenType driver. */ | |
582 | /* */ | |
583 | LOCAL_FUNC | |
584 | void T2_Done_Driver( T2_Driver driver ) | |
585 | { | |
586 | /* destroy extensions registry if needed */ | |
587 | ||
588 | #ifdef TT_CONFIG_OPTION_EXTEND_ENGINE | |
589 | ||
590 | TT_Done_Extensions( driver ); | |
591 | ||
592 | #else | |
593 | ||
594 | FT_UNUSED( driver ); | |
595 | ||
596 | #endif | |
597 | } | |
598 | ||
599 | ||
600 | /* END */ |