1 /***************************************************************************/
5 /* SFNT object management (base). */
7 /* Copyright 1996-2001 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
22 #include FT_INTERNAL_SFNT_H
23 #include FT_INTERNAL_POSTSCRIPT_NAMES_H
24 #include FT_TRUETYPE_IDS_H
25 #include FT_TRUETYPE_TAGS_H
30 /*************************************************************************/
32 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
33 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
34 /* messages during execution. */
37 #define FT_COMPONENT trace_sfobjs
40 /*************************************************************************/
46 /* Returns a given ENGLISH name record in ASCII. */
49 /* face :: A handle to the source face object. */
51 /* nameid :: The name id of the name record to return. */
54 /* Character string. NULL if no name is present. */
57 Get_Name( TT_Face face,
60 FT_Memory memory = face->root.memory;
63 FT_Bool wide_chars = 1;
66 rec = face->name_table.names;
67 for ( n = 0; n < face->name_table.numNameRecords; n++, rec++ )
69 if ( rec->nameID == nameid )
71 /* found the name -- now create an ASCII string from it */
75 /* test for Microsoft English language */
76 if ( rec->platformID == TT_PLATFORM_MICROSOFT &&
77 rec->encodingID <= TT_MS_ID_UNICODE_CS &&
78 ( rec->languageID & 0x3FF ) == 0x009 )
81 /* test for Apple Unicode encoding */
82 else if ( rec->platformID == TT_PLATFORM_APPLE_UNICODE )
85 /* test for Apple Roman */
86 else if ( rec->platformID == TT_PLATFORM_MACINTOSH &&
87 rec->languageID == TT_MAC_ID_ROMAN )
93 /* found a Unicode name */
105 len = (FT_UInt)rec->stringLength / 2;
106 if ( MEM_Alloc( string, len + 1 ) )
109 for ( m = 0; m < len; m ++ )
110 string[m] = rec->string[2 * m + 1];
114 len = rec->stringLength;
115 if ( MEM_Alloc( string, len + 1 ) )
118 MEM_Copy( string, rec->string, len );
132 find_encoding( int platform_id,
135 typedef struct TEncoding
139 FT_Encoding encoding;
144 const TEncoding tt_encodings[] =
146 { TT_PLATFORM_ISO, -1, ft_encoding_unicode },
148 { TT_PLATFORM_APPLE_UNICODE, -1, ft_encoding_unicode },
150 { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, ft_encoding_apple_roman },
152 { TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, ft_encoding_symbol },
153 { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, ft_encoding_unicode },
154 { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, ft_encoding_unicode },
155 { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, ft_encoding_sjis },
156 { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, ft_encoding_gb2312 },
157 { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, ft_encoding_big5 },
158 { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, ft_encoding_wansung },
159 { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, ft_encoding_johab }
162 const TEncoding *cur, *limit;
166 limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] );
168 for ( ; cur < limit; cur++ )
170 if ( cur->platform_id == platform_id )
172 if ( cur->encoding_id == encoding_id ||
173 cur->encoding_id == -1 )
174 return cur->encoding;
178 return ft_encoding_none;
182 FT_LOCAL_DEF FT_Error
183 SFNT_Init_Face( FT_Stream stream,
187 FT_Parameter* params )
190 FT_Library library = face->root.driver->root.library;
191 SFNT_Interface* sfnt;
192 SFNT_Header sfnt_header;
194 /* for now, parameters are unused */
195 FT_UNUSED( num_params );
198 sfnt = (SFNT_Interface*)face->sfnt;
201 sfnt = (SFNT_Interface*)FT_Get_Module_Interface( library, "sfnt" );
204 error = SFNT_Err_Invalid_File_Format;
209 face->goto_table = sfnt->goto_table;
212 if ( !face->psnames )
214 face->psnames = (PSNames_Interface*)
215 FT_Get_Module_Interface( library, "psnames" );
218 /* check that we have a valid TrueType file */
219 error = sfnt->load_sfnt_header( face, stream, face_index, &sfnt_header );
223 face->format_tag = sfnt_header.format_tag;
224 face->num_tables = sfnt_header.num_tables;
226 /* Load font directory */
227 error = sfnt->load_directory( face, stream, &sfnt_header );
231 face->root.num_faces = face->ttc_header.count;
232 if ( face->root.num_faces < 1 )
233 face->root.num_faces = 1;
241 #define LOAD_( x ) ( ( error = sfnt->load_##x( face, stream ) ) \
245 FT_LOCAL_DEF FT_Error
246 SFNT_Load_Face( FT_Stream stream,
250 FT_Parameter* params )
254 FT_Bool is_apple_sbit;
256 SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt;
258 FT_UNUSED( face_index );
259 FT_UNUSED( num_params );
265 /* We now support two SFNT-based bitmapped font formats. They */
266 /* are recognized easily as they do not include a `glyf' */
269 /* The first format comes from Apple, and uses a table named */
270 /* `bhed' instead of `head' to store the font header (using */
271 /* the same format). It also doesn't include horizontal and */
272 /* vertical metrics tables (i.e. `hhea' and `vhea' tables are */
275 /* The other format comes from Microsoft, and is used with */
276 /* WinCE/PocketPC. It looks like a standard TTF, except that */
277 /* it doesn't contain outlines. */
280 /* do we have outlines in there? */
281 has_outline = FT_BOOL( ( TT_LookUp_Table( face, TTAG_glyf ) != 0 ) ||
282 ( TT_LookUp_Table( face, TTAG_CFF ) != 0 ) );
285 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
287 /* if this font doesn't contain outlines, we try to load */
290 is_apple_sbit = FT_BOOL( !LOAD_( bitmap_header ) );
292 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
294 /* load the font header (`head' table) if this isn't an Apple */
296 if ( !is_apple_sbit && LOAD_( header ) )
299 /* load other tables */
300 if ( LOAD_( max_profile ) ||
306 /* do not load the metrics headers and tables if this is an Apple */
308 if ( !is_apple_sbit )
310 /* load the `hhea' and `hmtx' tables at once */
311 error = sfnt->load_metrics( face, stream, 0 );
315 /* try to load the `vhea' and `vmtx' tables at once */
316 error = sfnt->load_metrics( face, stream, 1 );
324 /* the optional tables */
326 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
328 /* embedded bitmap support. */
329 if ( sfnt->load_sbits && LOAD_( sbits ) )
331 /* return an error if this font file has no outlines */
332 if ( error == SFNT_Err_Table_Missing && has_outline )
337 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
339 if ( LOAD_( hdmx ) ||
345 #ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
346 if ( ( error = TT_Extension_Create( face ) ) != SFNT_Err_Ok )
350 face->root.family_name = Get_Name( face, TT_NAME_ID_FONT_FAMILY );
351 face->root.style_name = Get_Name( face, TT_NAME_ID_FONT_SUBFAMILY );
353 /* now set up root fields */
355 FT_Face root = &face->root;
362 memory = root->memory;
364 /*********************************************************************/
366 /* Compute face flags. */
368 if ( has_outline == TRUE )
369 flags = FT_FACE_FLAG_SCALABLE; /* scalable outlines */
371 flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */
372 FT_FACE_FLAG_HORIZONTAL; /* horizontal data */
374 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
375 /* might need more polish to detect the presence of a Postscript */
376 /* name table in the font */
377 flags |= FT_FACE_FLAG_GLYPH_NAMES;
380 /* fixed width font? */
381 if ( face->postscript.isFixedPitch )
382 flags |= FT_FACE_FLAG_FIXED_WIDTH;
384 /* vertical information? */
385 if ( face->vertical_info )
386 flags |= FT_FACE_FLAG_VERTICAL;
388 /* kerning available ? */
389 if ( face->kern_pairs )
390 flags |= FT_FACE_FLAG_KERNING;
392 root->face_flags = flags;
394 /*********************************************************************/
396 /* Compute style flags. */
399 if ( has_outline == TRUE && face->os2.version != 0xFFFF )
401 /* we have an OS/2 table; use the `fsSelection' field */
402 if ( face->os2.fsSelection & 1 )
403 flags |= FT_STYLE_FLAG_ITALIC;
405 if ( face->os2.fsSelection & 32 )
406 flags |= FT_STYLE_FLAG_BOLD;
410 /* this is an old Mac font, use the header field */
411 if ( face->header.Mac_Style & 1 )
412 flags |= FT_STYLE_FLAG_BOLD;
414 if ( face->header.Mac_Style & 2 )
415 flags |= FT_STYLE_FLAG_ITALIC;
418 root->style_flags = flags;
420 /*********************************************************************/
422 /* Polish the charmaps. */
424 /* Try to set the charmap encoding according to the platform & */
425 /* encoding ID of each charmap. */
427 charmap = face->charmaps;
428 root->num_charmaps = face->num_charmaps;
430 /* allocate table of pointers */
431 if ( ALLOC_ARRAY( root->charmaps, root->num_charmaps, FT_CharMap ) )
434 for ( n = 0; n < root->num_charmaps; n++, charmap++ )
436 FT_Int platform = charmap->cmap.platformID;
437 FT_Int encoding = charmap->cmap.platformEncodingID;
440 charmap->root.face = (FT_Face)face;
441 charmap->root.platform_id = (FT_UShort)platform;
442 charmap->root.encoding_id = (FT_UShort)encoding;
443 charmap->root.encoding = find_encoding( platform, encoding );
445 /* now, set root->charmap with a unicode charmap */
446 /* wherever available */
447 if ( !root->charmap &&
448 charmap->root.encoding == ft_encoding_unicode )
449 root->charmap = (FT_CharMap)charmap;
451 root->charmaps[n] = (FT_CharMap)charmap;
454 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
456 if ( face->num_sbit_strikes )
458 root->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
461 /* I don't know criteria whether layout is horizontal or vertical */
462 if ( has_outline.... )
465 root->face_flags |= FT_FACE_FLAG_VERTICAL;
468 root->num_fixed_sizes = face->num_sbit_strikes;
470 if ( ALLOC_ARRAY( root->available_sizes,
471 face->num_sbit_strikes,
475 for ( n = 0 ; n < face->num_sbit_strikes ; n++ )
477 root->available_sizes[n].width =
478 face->sbit_strikes[n].x_ppem;
480 root->available_sizes[n].height =
481 face->sbit_strikes[n].y_ppem;
486 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
489 root->num_fixed_sizes = 0;
490 root->available_sizes = 0;
493 /*********************************************************************/
495 /* Set up metrics. */
497 if ( has_outline == TRUE )
499 /* XXX What about if outline header is missing */
500 /* (e.g. sfnt wrapped outline)? */
501 root->bbox.xMin = face->header.xMin;
502 root->bbox.yMin = face->header.yMin;
503 root->bbox.xMax = face->header.xMax;
504 root->bbox.yMax = face->header.yMax;
505 root->units_per_EM = face->header.Units_Per_EM;
508 /* XXX: Computing the ascender/descender/height is very different */
509 /* from what the specification tells you. Apparently, we */
510 /* must be careful because */
512 /* - not all fonts have an OS/2 table; in this case, we take */
513 /* the values in the horizontal header. However, these */
514 /* values very often are not reliable. */
516 /* - otherwise, the correct typographic values are in the */
517 /* sTypoAscender, sTypoDescender & sTypoLineGap fields. */
519 /* However, certains fonts have these fields set to 0. */
520 /* Rather, they have usWinAscent & usWinDescent correctly */
521 /* set (but with different values). */
523 /* As an example, Arial Narrow is implemented through four */
524 /* files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */
526 /* Strangely, all fonts have the same values in their */
527 /* sTypoXXX fields, except ARIALNB which sets them to 0. */
529 /* On the other hand, they all have different */
530 /* usWinAscent/Descent values -- as a conclusion, the OS/2 */
531 /* table cannot be used to compute the text height reliably! */
534 /* The ascender/descender/height are computed from the OS/2 table */
535 /* when found. Otherwise, they're taken from the horizontal */
539 root->ascender = face->horizontal.Ascender;
540 root->descender = face->horizontal.Descender;
542 root->height = (FT_Short)( root->ascender - root->descender +
543 face->horizontal.Line_Gap );
545 /* if the line_gap is 0, we add an extra 15% to the text height -- */
546 /* this computation is based on various versions of Times New Roman */
547 if ( face->horizontal.Line_Gap == 0 )
548 root->height = (FT_Short)( ( root->height * 115 + 50 ) / 100 );
552 /* some fonts have the OS/2 "sTypoAscender", "sTypoDescender" & */
553 /* "sTypoLineGap" fields set to 0, like ARIALNB.TTF */
554 if ( face->os2.version != 0xFFFF && root->ascender )
559 root->ascender = face->os2.sTypoAscender;
560 root->descender = -face->os2.sTypoDescender;
562 height = root->ascender + root->descender + face->os2.sTypoLineGap;
563 if ( height > root->height )
564 root->height = height;
569 root->max_advance_width = face->horizontal.advance_Width_Max;
571 root->max_advance_height = (FT_Short)( face->vertical_info
572 ? face->vertical.advance_Height_Max
575 root->underline_position = face->postscript.underlinePosition;
576 root->underline_thickness = face->postscript.underlineThickness;
578 /* root->max_points -- already set up */
579 /* root->max_contours -- already set up */
592 SFNT_Done_Face( TT_Face face )
594 FT_Memory memory = face->root.memory;
595 SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt;
600 /* destroy the postscript names table if it is loaded */
601 if ( sfnt->free_psnames )
602 sfnt->free_psnames( face );
604 /* destroy the embedded bitmaps table if it is loaded */
605 if ( sfnt->free_sbits )
606 sfnt->free_sbits( face );
609 /* freeing the kerning table */
610 FREE( face->kern_pairs );
611 face->num_kern_pairs = 0;
613 /* freeing the collection table */
614 FREE( face->ttc_header.offsets );
615 face->ttc_header.count = 0;
617 /* freeing table directory */
618 FREE( face->dir_tables );
619 face->num_tables = 0;
621 /* freeing the character mapping tables */
622 if ( sfnt && sfnt->load_charmaps )
627 for ( n = 0; n < face->num_charmaps; n++ )
628 sfnt->free_charmap( face, &face->charmaps[n].cmap );
631 FREE( face->charmaps );
632 face->num_charmaps = 0;
634 FREE( face->root.charmaps );
635 face->root.num_charmaps = 0;
636 face->root.charmap = 0;
638 /* freeing the horizontal metrics */
639 FREE( face->horizontal.long_metrics );
640 FREE( face->horizontal.short_metrics );
642 /* freeing the vertical ones, if any */
643 if ( face->vertical_info )
645 FREE( face->vertical.long_metrics );
646 FREE( face->vertical.short_metrics );
647 face->vertical_info = 0;
650 /* freeing the gasp table */
651 FREE( face->gasp.gaspRanges );
652 face->gasp.numRanges = 0;
654 /* freeing the name table */
655 sfnt->free_names( face );
657 /* freeing the hdmx table */
658 sfnt->free_hdmx( face );
660 /* freeing family and style name */
661 FREE( face->root.family_name );
662 FREE( face->root.style_name );
664 /* freeing sbit size table */
665 face->root.num_fixed_sizes = 0;
666 if ( face->root.available_sizes )
667 FREE( face->root.available_sizes );