]>
Commit | Line | Data |
---|---|---|
cabec872 RR |
1 | /***************************************************************************/ |
2 | /* */ | |
3 | /* sfobjs.c */ | |
4 | /* */ | |
5 | /* SFNT object management (base). */ | |
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 | #ifdef FT_FLAT_COMPILE | |
20 | ||
21 | #include "sfobjs.h" | |
22 | ||
23 | #else | |
24 | ||
25 | #include <sfnt/sfobjs.h> | |
26 | ||
27 | #endif | |
28 | ||
29 | ||
30 | #include <freetype/internal/sfnt.h> | |
31 | #include <freetype/internal/psnames.h> | |
32 | #include <freetype/ttnameid.h> | |
33 | #include <freetype/internal/tterrors.h> | |
34 | ||
35 | ||
36 | /*************************************************************************/ | |
37 | /* */ | |
38 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | |
39 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | |
40 | /* messages during execution. */ | |
41 | /* */ | |
42 | #undef FT_COMPONENT | |
43 | #define FT_COMPONENT trace_sfobjs | |
44 | ||
45 | ||
46 | /*************************************************************************/ | |
47 | /* */ | |
48 | /* <Function> */ | |
49 | /* Get_Name */ | |
50 | /* */ | |
51 | /* <Description> */ | |
52 | /* Returns a given ENGLISH name record in ASCII. */ | |
53 | /* */ | |
54 | /* <Input> */ | |
55 | /* face :: A handle to the source face object. */ | |
56 | /* */ | |
57 | /* nameid :: The name id of the name record to return. */ | |
58 | /* */ | |
59 | /* <Return> */ | |
60 | /* Character string. NULL if no name is present. */ | |
61 | /* */ | |
62 | static | |
63 | FT_String* Get_Name( TT_Face face, | |
64 | FT_UShort nameid ) | |
65 | { | |
66 | FT_Memory memory = face->root.memory; | |
67 | FT_UShort n; | |
68 | TT_NameRec* rec; | |
69 | FT_Bool wide_chars = 1; | |
70 | ||
71 | ||
72 | rec = face->name_table.names; | |
73 | for ( n = 0; n < face->name_table.numNameRecords; n++, rec++ ) | |
74 | { | |
75 | if ( rec->nameID == nameid ) | |
76 | { | |
77 | /* found the name -- now create an ASCII string from it */ | |
78 | FT_Bool found = 0; | |
79 | ||
80 | ||
81 | /* test for Microsoft English language */ | |
82 | if ( rec->platformID == TT_PLATFORM_MICROSOFT && | |
83 | rec->encodingID <= TT_MS_ID_UNICODE_CS && | |
84 | ( rec->languageID & 0x3FF ) == 0x009 ) | |
85 | found = 1; | |
86 | ||
87 | /* test for Apple Unicode encoding */ | |
88 | else if ( rec->platformID == TT_PLATFORM_APPLE_UNICODE ) | |
89 | found = 1; | |
90 | ||
91 | /* test for Apple Roman */ | |
92 | else if ( rec->platformID == TT_PLATFORM_MACINTOSH && | |
93 | rec->languageID == TT_MAC_ID_ROMAN ) | |
94 | { | |
95 | found = 1; | |
96 | wide_chars = 0; | |
97 | } | |
98 | ||
99 | /* found a Unicode name */ | |
100 | if ( found ) | |
101 | { | |
102 | FT_String* string; | |
103 | FT_UInt len; | |
104 | ||
105 | ||
106 | if ( wide_chars ) | |
107 | { | |
108 | FT_UInt m; | |
109 | ||
110 | ||
111 | len = (FT_UInt)rec->stringLength / 2; | |
112 | if ( MEM_Alloc( string, len + 1 ) ) | |
113 | return NULL; | |
114 | ||
115 | for ( m = 0; m < len; m ++ ) | |
116 | string[m] = rec->string[2 * m + 1]; | |
117 | } | |
118 | else | |
119 | { | |
120 | len = rec->stringLength; | |
121 | if ( MEM_Alloc( string, len + 1 ) ) | |
122 | return NULL; | |
123 | ||
124 | MEM_Copy( string, rec->string, len ); | |
125 | } | |
126 | ||
127 | string[len] = '\0'; | |
128 | return string; | |
129 | } | |
130 | } | |
131 | } | |
132 | ||
133 | return NULL; | |
134 | } | |
135 | ||
136 | ||
137 | static | |
138 | FT_Encoding find_encoding( int platform_id, | |
139 | int encoding_id ) | |
140 | { | |
141 | typedef struct TEncoding | |
142 | { | |
143 | int platform_id; | |
144 | int encoding_id; | |
145 | FT_Encoding encoding; | |
146 | ||
147 | } TEncoding; | |
148 | ||
149 | static | |
150 | const TEncoding tt_encodings[] = | |
151 | { | |
152 | { TT_PLATFORM_ISO, -1, ft_encoding_unicode }, | |
153 | ||
154 | { TT_PLATFORM_APPLE_UNICODE, -1, ft_encoding_unicode }, | |
155 | ||
156 | { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, ft_encoding_apple_roman }, | |
157 | ||
158 | { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, ft_encoding_unicode }, | |
159 | { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, ft_encoding_sjis }, | |
160 | { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, ft_encoding_gb2312 }, | |
161 | { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, ft_encoding_big5 }, | |
162 | { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, ft_encoding_wansung }, | |
163 | { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, ft_encoding_johab } | |
164 | }; | |
165 | ||
166 | const TEncoding *cur, *limit; | |
167 | ||
168 | ||
169 | cur = tt_encodings; | |
170 | limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] ); | |
171 | ||
172 | for ( ; cur < limit; cur++ ) | |
173 | { | |
174 | if ( cur->platform_id == platform_id ) | |
175 | { | |
176 | if ( cur->encoding_id == encoding_id || | |
177 | cur->encoding_id == -1 ) | |
178 | return cur->encoding; | |
179 | } | |
180 | } | |
181 | ||
182 | return ft_encoding_none; | |
183 | } | |
184 | ||
185 | ||
186 | LOCAL_FUNC | |
187 | FT_Error SFNT_Init_Face( FT_Stream stream, | |
188 | TT_Face face, | |
189 | FT_Int face_index, | |
190 | FT_Int num_params, | |
191 | FT_Parameter* params ) | |
192 | { | |
193 | FT_Error error; | |
194 | FT_Library library = face->root.driver->root.library; | |
195 | SFNT_Interface* sfnt; | |
196 | SFNT_Header sfnt_header; | |
197 | ||
198 | /* for now, parameters are unused */ | |
199 | FT_UNUSED( num_params ); | |
200 | FT_UNUSED( params ); | |
201 | ||
202 | sfnt = (SFNT_Interface*)face->sfnt; | |
203 | if ( !sfnt ) | |
204 | { | |
205 | sfnt = (SFNT_Interface*)FT_Get_Module_Interface( library, "sfnt" ); | |
206 | if ( !sfnt ) | |
207 | { | |
208 | error = FT_Err_Invalid_File_Format; | |
209 | goto Exit; | |
210 | } | |
211 | ||
212 | face->sfnt = sfnt; | |
213 | face->goto_table = sfnt->goto_table; | |
214 | } | |
215 | ||
216 | if ( !face->psnames ) | |
217 | { | |
218 | face->psnames = (PSNames_Interface*) | |
219 | FT_Get_Module_Interface( library, "psnames" ); | |
220 | } | |
221 | ||
222 | /* check that we have a valid TrueType file */ | |
223 | error = sfnt->load_sfnt_header( face, stream, face_index, &sfnt_header ); | |
224 | if ( error ) | |
225 | goto Exit; | |
226 | ||
227 | face->format_tag = sfnt_header.format_tag; | |
228 | face->num_tables = sfnt_header.num_tables; | |
229 | ||
230 | /* Load font directory */ | |
231 | error = sfnt->load_directory( face, stream, &sfnt_header ); | |
232 | if ( error ) | |
233 | goto Exit; | |
234 | ||
235 | face->root.num_faces = face->ttc_header.count; | |
236 | if ( face->root.num_faces < 1 ) | |
237 | face->root.num_faces = 1; | |
238 | ||
239 | Exit: | |
240 | return error; | |
241 | } | |
242 | ||
243 | ||
244 | #undef LOAD_ | |
245 | #define LOAD_( x ) ( ( error = sfnt->load_##x( face, stream ) ) \ | |
246 | != TT_Err_Ok ) | |
247 | ||
248 | ||
249 | LOCAL_FUNC | |
250 | FT_Error SFNT_Load_Face( FT_Stream stream, | |
251 | TT_Face face, | |
252 | FT_Int face_index, | |
253 | FT_Int num_params, | |
254 | FT_Parameter* params ) | |
255 | { | |
256 | FT_Error error; | |
257 | SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt; | |
258 | ||
259 | FT_UNUSED( face_index ); | |
260 | FT_UNUSED( num_params ); | |
261 | FT_UNUSED( params ); | |
262 | ||
263 | ||
264 | /* Load tables */ | |
265 | if ( LOAD_( header ) || | |
266 | LOAD_( max_profile ) || | |
267 | ||
268 | /* load the `hhea' & `hmtx' tables at once */ | |
269 | ( error = sfnt->load_metrics( face, stream, 0 ) ) != TT_Err_Ok || | |
270 | ||
271 | /* try to load the `vhea' & `vmtx' at once if present */ | |
272 | ( error = sfnt->load_metrics( face, stream, 1 ) ) != TT_Err_Ok || | |
273 | ||
274 | LOAD_( charmaps ) || | |
275 | LOAD_( names ) || | |
276 | LOAD_( os2 ) || | |
277 | LOAD_( psnames ) ) | |
278 | goto Exit; | |
279 | ||
280 | /* the optional tables */ | |
281 | ||
282 | #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS | |
283 | /* embedded bitmap support. */ | |
284 | if ( sfnt->load_sbits && LOAD_( sbits ) ) | |
285 | goto Exit; | |
286 | #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ | |
287 | ||
288 | if ( LOAD_( hdmx ) || | |
289 | LOAD_( gasp ) || | |
290 | LOAD_( kerning ) || | |
291 | LOAD_( pclt ) ) | |
292 | goto Exit; | |
293 | ||
294 | #ifdef TT_CONFIG_OPTION_EXTEND_ENGINE | |
295 | if ( ( error = TT_Extension_Create( face ) ) != TT_Err_Ok ) | |
296 | goto Exit; | |
297 | #endif | |
298 | ||
299 | face->root.family_name = Get_Name( face, TT_NAME_ID_FONT_FAMILY ); | |
300 | face->root.style_name = Get_Name( face, TT_NAME_ID_FONT_SUBFAMILY ); | |
301 | ||
302 | /* now set up root fields */ | |
303 | { | |
304 | FT_Face root = &face->root; | |
305 | FT_Int flags; | |
306 | TT_CharMap charmap; | |
307 | FT_Int n; | |
308 | FT_Memory memory; | |
309 | ||
310 | ||
311 | memory = root->memory; | |
312 | ||
313 | /*********************************************************************/ | |
314 | /* */ | |
315 | /* Compute face flags. */ | |
316 | /* */ | |
317 | flags = FT_FACE_FLAG_SCALABLE | /* scalable outlines */ | |
318 | FT_FACE_FLAG_SFNT | /* SFNT file format */ | |
319 | FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ | |
320 | ||
321 | #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES | |
322 | /* might need more polish to detect the presence of a Postscript */ | |
323 | /* name table in the font */ | |
324 | flags |= FT_FACE_FLAG_GLYPH_NAMES; | |
325 | #endif | |
326 | ||
327 | /* fixed width font? */ | |
328 | if ( face->postscript.isFixedPitch ) | |
329 | flags |= FT_FACE_FLAG_FIXED_WIDTH; | |
330 | ||
331 | /* vertical information? */ | |
332 | if ( face->vertical_info ) | |
333 | flags |= FT_FACE_FLAG_VERTICAL; | |
334 | ||
335 | /* kerning available ? */ | |
336 | if ( face->kern_pairs ) | |
337 | flags |= FT_FACE_FLAG_KERNING; | |
338 | ||
339 | root->face_flags = flags; | |
340 | ||
341 | /*********************************************************************/ | |
342 | /* */ | |
343 | /* Compute style flags. */ | |
344 | /* */ | |
345 | flags = 0; | |
346 | ||
347 | if ( face->os2.version != 0xFFFF ) | |
348 | { | |
349 | /* we have an OS/2 table; use the `fsSelection' field */ | |
350 | if ( face->os2.fsSelection & 1 ) | |
351 | flags |= FT_STYLE_FLAG_ITALIC; | |
352 | ||
353 | if ( face->os2.fsSelection & 32 ) | |
354 | flags |= FT_STYLE_FLAG_BOLD; | |
355 | } | |
356 | else | |
357 | { | |
358 | /* this is an old Mac font, use the header field */ | |
359 | if ( face->header.Mac_Style & 1 ) | |
360 | flags |= FT_STYLE_FLAG_BOLD; | |
361 | ||
362 | if ( face->header.Mac_Style & 2 ) | |
363 | flags |= FT_STYLE_FLAG_ITALIC; | |
364 | } | |
365 | ||
366 | root->style_flags = flags; | |
367 | ||
368 | /*********************************************************************/ | |
369 | /* */ | |
370 | /* Polish the charmaps. */ | |
371 | /* */ | |
372 | /* Try to set the charmap encoding according to the platform & */ | |
373 | /* encoding ID of each charmap. */ | |
374 | /* */ | |
375 | charmap = face->charmaps; | |
376 | root->num_charmaps = face->num_charmaps; | |
377 | ||
378 | /* allocate table of pointers */ | |
379 | if ( ALLOC_ARRAY( root->charmaps, root->num_charmaps, FT_CharMap ) ) | |
380 | goto Exit; | |
381 | ||
382 | for ( n = 0; n < root->num_charmaps; n++, charmap++ ) | |
383 | { | |
384 | FT_Int platform = charmap->cmap.platformID; | |
385 | FT_Int encoding = charmap->cmap.platformEncodingID; | |
386 | ||
387 | ||
388 | charmap->root.face = (FT_Face)face; | |
389 | charmap->root.platform_id = platform; | |
390 | charmap->root.encoding_id = encoding; | |
391 | charmap->root.encoding = find_encoding( platform, encoding ); | |
392 | ||
393 | /* now, set root->charmap with a unicode charmap */ | |
394 | /* wherever available */ | |
395 | if ( !root->charmap && | |
396 | charmap->root.encoding == ft_encoding_unicode ) | |
397 | root->charmap = (FT_CharMap)charmap; | |
398 | ||
399 | root->charmaps[n] = (FT_CharMap)charmap; | |
400 | } | |
401 | ||
402 | #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS | |
403 | ||
404 | if ( face->num_sbit_strikes ) | |
405 | { | |
406 | root->num_fixed_sizes = face->num_sbit_strikes; | |
407 | if ( ALLOC_ARRAY( root->available_sizes, | |
408 | face->num_sbit_strikes, | |
409 | FT_Bitmap_Size ) ) | |
410 | return error; | |
411 | ||
412 | for ( n = 0 ; n < face->num_sbit_strikes ; n++ ) | |
413 | { | |
414 | root->available_sizes[n].width = | |
415 | face->sbit_strikes[n].x_ppem; | |
416 | root->available_sizes[n].height = | |
417 | face->sbit_strikes[n].y_ppem; | |
418 | } | |
419 | } | |
420 | else | |
421 | ||
422 | #else /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ | |
423 | ||
424 | { | |
425 | root->num_fixed_sizes = 0; | |
426 | root->available_sizes = 0; | |
427 | } | |
428 | ||
429 | #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ | |
430 | ||
431 | /*********************************************************************/ | |
432 | /* */ | |
433 | /* Set up metrics. */ | |
434 | /* */ | |
435 | root->bbox.xMin = face->header.xMin; | |
436 | root->bbox.yMin = face->header.yMin; | |
437 | root->bbox.xMax = face->header.xMax; | |
438 | root->bbox.yMax = face->header.yMax; | |
439 | root->units_per_EM = face->header.Units_Per_EM; | |
440 | ||
441 | /* The ascender/descender/height are computed from the OS/2 table */ | |
442 | /* when found. Otherwise, they're taken from the horizontal header. */ | |
443 | if ( face->os2.version != 0xFFFF ) | |
444 | { | |
445 | root->ascender = face->os2.sTypoAscender; | |
446 | root->descender = -face->os2.sTypoDescender; | |
447 | root->height = root->ascender + root->descender + | |
448 | face->os2.sTypoLineGap; | |
449 | } | |
450 | else | |
451 | { | |
452 | root->ascender = face->horizontal.Ascender; | |
453 | root->descender = face->horizontal.Descender; | |
454 | root->height = root->ascender + root->descender + | |
455 | face->horizontal.Line_Gap; | |
456 | } | |
457 | ||
458 | root->max_advance_width = face->horizontal.advance_Width_Max; | |
459 | ||
460 | root->max_advance_height = face->vertical_info | |
461 | ? face->vertical.advance_Height_Max | |
462 | : root->height; | |
463 | ||
464 | root->underline_position = face->postscript.underlinePosition; | |
465 | root->underline_thickness = face->postscript.underlineThickness; | |
466 | ||
467 | /* root->max_points -- already set up */ | |
468 | /* root->max_contours -- already set up */ | |
469 | } | |
470 | ||
471 | Exit: | |
472 | return error; | |
473 | } | |
474 | ||
475 | ||
476 | #undef LOAD_ | |
477 | ||
478 | ||
479 | LOCAL_FUNC | |
480 | void SFNT_Done_Face( TT_Face face ) | |
481 | { | |
482 | FT_Memory memory = face->root.memory; | |
483 | SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt; | |
484 | ||
485 | ||
486 | if ( sfnt ) | |
487 | { | |
488 | /* destroy the postscript names table if it is loaded */ | |
489 | if ( sfnt->free_psnames ) | |
490 | sfnt->free_psnames( face ); | |
491 | ||
492 | /* destroy the embedded bitmaps table if it is loaded */ | |
493 | if ( sfnt->free_sbits ) | |
494 | sfnt->free_sbits( face ); | |
495 | } | |
496 | ||
497 | /* freeing the kerning table */ | |
498 | FREE( face->kern_pairs ); | |
499 | face->num_kern_pairs = 0; | |
500 | ||
501 | /* freeing the collection table */ | |
502 | FREE( face->ttc_header.offsets ); | |
503 | face->ttc_header.count = 0; | |
504 | ||
505 | /* freeing table directory */ | |
506 | FREE( face->dir_tables ); | |
507 | face->num_tables = 0; | |
508 | ||
509 | /* freeing the character mapping tables */ | |
510 | if ( sfnt && sfnt->load_charmaps ) | |
511 | { | |
512 | FT_UShort n; | |
513 | ||
514 | ||
515 | for ( n = 0; n < face->num_charmaps; n++ ) | |
516 | sfnt->free_charmap( face, &face->charmaps[n].cmap ); | |
517 | } | |
518 | ||
519 | FREE( face->charmaps ); | |
520 | face->num_charmaps = 0; | |
521 | ||
522 | FREE( face->root.charmaps ); | |
523 | face->root.num_charmaps = 0; | |
524 | face->root.charmap = 0; | |
525 | ||
526 | /* freeing the horizontal metrics */ | |
527 | FREE( face->horizontal.long_metrics ); | |
528 | FREE( face->horizontal.short_metrics ); | |
529 | ||
530 | /* freeing the vertical ones, if any */ | |
531 | if ( face->vertical_info ) | |
532 | { | |
533 | FREE( face->vertical.long_metrics ); | |
534 | FREE( face->vertical.short_metrics ); | |
535 | face->vertical_info = 0; | |
536 | } | |
537 | ||
538 | /* freeing the gasp table */ | |
539 | FREE( face->gasp.gaspRanges ); | |
540 | face->gasp.numRanges = 0; | |
541 | ||
542 | /* freeing the name table */ | |
543 | sfnt->free_names( face ); | |
544 | ||
545 | /* freeing the hdmx table */ | |
546 | sfnt->free_hdmx( face ); | |
547 | ||
548 | /* freeing family and style name */ | |
549 | FREE( face->root.family_name ); | |
550 | FREE( face->root.style_name ); | |
551 | ||
552 | /* freeing sbit size table */ | |
553 | face->root.num_fixed_sizes = 0; | |
554 | if ( face->root.available_sizes ) | |
555 | FREE( face->root.available_sizes ); | |
556 | ||
557 | face->sfnt = 0; | |
558 | } | |
559 | ||
560 | ||
561 | /* END */ |