1
/***************************************************************************/
5
/* SFNT object management (base). */
7
/* Copyright 1996-2001, 2002, 2003, 2004 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
/***************************************************************************/
23
#include FT_INTERNAL_SFNT_H
24
#include FT_TRUETYPE_IDS_H
25
#include FT_TRUETYPE_TAGS_H
26
#include FT_SERVICE_POSTSCRIPT_CMAPS_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
41
/* convert a UTF-16 name entry to ASCII */
43
tt_name_entry_ascii_from_utf16( TT_NameEntry entry,
48
FT_Byte* read = (FT_Byte*)entry->string;
51
len = (FT_UInt)entry->stringLength / 2;
53
if ( FT_MEM_NEW_ARRAY( string, len + 1 ) )
56
for ( n = 0; n < len; n++ )
58
code = FT_NEXT_USHORT( read );
59
if ( code < 32 || code > 127 )
62
string[n] = (char)code;
71
/* convert a UCS-4 name entry to ASCII */
73
tt_name_entry_ascii_from_ucs4( TT_NameEntry entry,
78
FT_Byte* read = (FT_Byte*)entry->string;
81
len = (FT_UInt)entry->stringLength / 4;
83
if ( FT_MEM_NEW_ARRAY( string, len + 1 ) )
86
for ( n = 0; n < len; n++ )
88
code = (FT_UInt)FT_NEXT_ULONG( read );
89
if ( code < 32 || code > 127 )
92
string[n] = (char)code;
101
/* convert an Apple Roman or symbol name entry to ASCII */
103
tt_name_entry_ascii_from_other( TT_NameEntry entry,
107
FT_UInt len, code, n;
108
FT_Byte* read = (FT_Byte*)entry->string;
111
len = (FT_UInt)entry->stringLength;
113
if ( FT_MEM_NEW_ARRAY( string, len + 1 ) )
116
for ( n = 0; n < len; n++ )
119
if ( code < 32 || code > 127 )
122
string[n] = (char)code;
131
typedef FT_String* (*TT_NameEntry_ConvertFunc)( TT_NameEntry entry,
135
/*************************************************************************/
138
/* tt_face_get_name */
141
/* Returns a given ENGLISH name record in ASCII. */
144
/* face :: A handle to the source face object. */
146
/* nameid :: The name id of the name record to return. */
149
/* Character string. NULL if no name is present. */
152
tt_face_get_name( TT_Face face,
155
FT_Memory memory = face->root.memory;
156
FT_String* result = NULL;
158
TT_NameEntryRec* rec;
159
FT_Int found_apple = -1;
160
FT_Int found_win = -1;
161
FT_Int found_unicode = -1;
163
FT_Bool is_english = 0;
165
TT_NameEntry_ConvertFunc convert;
168
rec = face->name_table.names;
169
for ( n = 0; n < face->num_names; n++, rec++ )
171
/* According to the OpenType 1.3 specification, only Microsoft or */
172
/* Apple platform IDs might be used in the `name' table. The */
173
/* `Unicode' platform is reserved for the `cmap' table, and the */
174
/* `Iso' one is deprecated. */
176
/* However, the Apple TrueType specification doesn't say the same */
177
/* thing and goes to suggest that all Unicode `name' table entries */
178
/* should be coded in UTF-16 (in big-endian format I suppose). */
180
if ( rec->nameID == nameid && rec->stringLength > 0 )
182
switch ( rec->platformID )
184
case TT_PLATFORM_APPLE_UNICODE:
185
case TT_PLATFORM_ISO:
186
/* there is `languageID' to check there. We should use this */
187
/* field only as a last solution when nothing else is */
193
case TT_PLATFORM_MACINTOSH:
194
if ( rec->languageID == TT_MAC_LANGID_ENGLISH )
199
case TT_PLATFORM_MICROSOFT:
200
/* we only take a non-English name when there is nothing */
201
/* else available in the font */
203
if ( found_win == -1 || ( rec->languageID & 0x3FF ) == 0x009 )
205
switch ( rec->encodingID )
207
case TT_MS_ID_SYMBOL_CS:
208
case TT_MS_ID_UNICODE_CS:
210
is_english = ( rec->languageID & 0x3FF ) == 0x009;
226
/* some fonts contain invalid Unicode or Macintosh formatted entries; */
227
/* we will thus favor names encoded in Windows formats if available */
228
/* (provided it is an English name) */
231
if ( found_win >= 0 && !( found_apple >= 0 && !is_english ) )
233
rec = face->name_table.names + found_win;
234
switch ( rec->encodingID )
236
case TT_MS_ID_UNICODE_CS:
237
case TT_MS_ID_SYMBOL_CS:
238
convert = tt_name_entry_ascii_from_utf16;
242
convert = tt_name_entry_ascii_from_ucs4;
249
else if ( found_apple >= 0 )
251
rec = face->name_table.names + found_apple;
252
convert = tt_name_entry_ascii_from_other;
254
else if ( found_unicode >= 0 )
256
rec = face->name_table.names + found_unicode;
257
convert = tt_name_entry_ascii_from_utf16;
260
if ( rec && convert )
262
if ( rec->string == NULL )
264
FT_Error error = SFNT_Err_Ok;
265
FT_Stream stream = face->name_table.stream;
270
if ( FT_QNEW_ARRAY ( rec->string, rec->stringLength ) ||
271
FT_STREAM_SEEK( rec->stringOffset ) ||
272
FT_STREAM_READ( rec->string, rec->stringLength ) )
274
FT_FREE( rec->string );
275
rec->stringLength = 0;
281
result = convert( rec, memory );
290
sfnt_find_encoding( int platform_id,
293
typedef struct TEncoding
297
FT_Encoding encoding;
302
const TEncoding tt_encodings[] =
304
{ TT_PLATFORM_ISO, -1, FT_ENCODING_UNICODE },
306
{ TT_PLATFORM_APPLE_UNICODE, -1, FT_ENCODING_UNICODE },
308
{ TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, FT_ENCODING_APPLE_ROMAN },
310
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, FT_ENCODING_MS_SYMBOL },
311
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, FT_ENCODING_UNICODE },
312
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, FT_ENCODING_UNICODE },
313
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, FT_ENCODING_SJIS },
314
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, FT_ENCODING_GB2312 },
315
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, FT_ENCODING_BIG5 },
316
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, FT_ENCODING_WANSUNG },
317
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, FT_ENCODING_JOHAB }
320
const TEncoding *cur, *limit;
324
limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] );
326
for ( ; cur < limit; cur++ )
328
if ( cur->platform_id == platform_id )
330
if ( cur->encoding_id == encoding_id ||
331
cur->encoding_id == -1 )
332
return cur->encoding;
336
return FT_ENCODING_NONE;
340
FT_LOCAL_DEF( FT_Error )
341
sfnt_init_face( FT_Stream stream,
345
FT_Parameter* params )
348
FT_Library library = face->root.driver->root.library;
350
SFNT_HeaderRec sfnt_header;
352
/* for now, parameters are unused */
353
FT_UNUSED( num_params );
357
sfnt = (SFNT_Service)face->sfnt;
360
sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" );
363
error = SFNT_Err_Invalid_File_Format;
368
face->goto_table = sfnt->goto_table;
371
FT_FACE_FIND_GLOBAL_SERVICE( face, face->psnames, POSTSCRIPT_CMAPS );
373
/* check that we have a valid TrueType file */
374
error = sfnt->load_sfnt_header( face, stream, face_index, &sfnt_header );
378
face->format_tag = sfnt_header.format_tag;
379
face->num_tables = sfnt_header.num_tables;
381
/* Load font directory */
382
error = sfnt->load_directory( face, stream, &sfnt_header );
386
face->root.num_faces = face->ttc_header.count;
387
if ( face->root.num_faces < 1 )
388
face->root.num_faces = 1;
396
#define LOAD_( x ) ( ( error = sfnt->load_##x( face, stream ) ) \
400
FT_LOCAL_DEF( FT_Error )
401
sfnt_load_face( FT_Stream stream,
405
FT_Parameter* params )
407
FT_Error error, psnames_error;
409
FT_Bool is_apple_sbit;
411
SFNT_Service sfnt = (SFNT_Service)face->sfnt;
413
FT_UNUSED( face_index );
414
FT_UNUSED( num_params );
420
/* We now support two SFNT-based bitmapped font formats. They */
421
/* are recognized easily as they do not include a `glyf' */
424
/* The first format comes from Apple, and uses a table named */
425
/* `bhed' instead of `head' to store the font header (using */
426
/* the same format). It also doesn't include horizontal and */
427
/* vertical metrics tables (i.e. `hhea' and `vhea' tables are */
430
/* The other format comes from Microsoft, and is used with */
431
/* WinCE/PocketPC. It looks like a standard TTF, except that */
432
/* it doesn't contain outlines. */
435
/* do we have outlines in there? */
436
#ifdef FT_CONFIG_OPTION_INCREMENTAL
437
has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 ||
438
tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
439
tt_face_lookup_table( face, TTAG_CFF ) != 0 );
441
has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
442
tt_face_lookup_table( face, TTAG_CFF ) != 0 );
447
#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
449
/* if this font doesn't contain outlines, we try to load */
452
is_apple_sbit = FT_BOOL( !LOAD_( bitmap_header ) );
454
#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
456
/* load the font header (`head' table) if this isn't an Apple */
458
if ( !is_apple_sbit && LOAD_( header ) )
461
/* the following tables are often not present in embedded TrueType */
462
/* fonts within PDF documents, so don't check for them. */
463
(void)LOAD_( max_profile );
464
(void)LOAD_( charmaps );
466
/* the following tables are optional in PCL fonts -- */
467
/* don't check for errors */
468
(void)LOAD_( names );
469
psnames_error = LOAD_( psnames );
471
/* do not load the metrics headers and tables if this is an Apple */
473
if ( !is_apple_sbit )
475
/* load the `hhea' and `hmtx' tables at once */
476
error = sfnt->load_metrics( face, stream, 0 );
480
/* try to load the `vhea' and `vmtx' tables at once */
481
error = sfnt->load_metrics( face, stream, 1 );
489
/* the optional tables */
491
#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
493
/* embedded bitmap support. */
494
if ( sfnt->load_sbits && LOAD_( sbits ) )
496
/* return an error if this font file has no outlines */
497
if ( error == SFNT_Err_Table_Missing && has_outline )
503
#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
505
if ( LOAD_( hdmx ) ||
511
face->root.family_name = tt_face_get_name( face,
512
TT_NAME_ID_FONT_FAMILY );
513
face->root.style_name = tt_face_get_name( face,
514
TT_NAME_ID_FONT_SUBFAMILY );
516
/* now set up root fields */
518
FT_Face root = &face->root;
523
memory = root->memory;
525
/*********************************************************************/
527
/* Compute face flags. */
529
if ( has_outline == TRUE )
530
flags = FT_FACE_FLAG_SCALABLE; /* scalable outlines */
532
flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */
533
FT_FACE_FLAG_HORIZONTAL; /* horizontal data */
535
#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
536
if ( psnames_error == SFNT_Err_Ok &&
537
face->postscript.FormatType != 0x00030000L )
538
flags |= FT_FACE_FLAG_GLYPH_NAMES;
541
/* fixed width font? */
542
if ( face->postscript.isFixedPitch )
543
flags |= FT_FACE_FLAG_FIXED_WIDTH;
545
/* vertical information? */
546
if ( face->vertical_info )
547
flags |= FT_FACE_FLAG_VERTICAL;
549
/* kerning available ? */
550
if ( face->kern_pairs )
551
flags |= FT_FACE_FLAG_KERNING;
553
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
554
/* Don't bother to load the tables unless somebody asks for them. */
555
/* No need to do work which will (probably) not be used. */
556
if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 &&
557
tt_face_lookup_table( face, TTAG_fvar ) != 0 &&
558
tt_face_lookup_table( face, TTAG_gvar ) != 0 )
559
flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
562
root->face_flags = flags;
564
/*********************************************************************/
566
/* Compute style flags. */
569
if ( has_outline == TRUE && face->os2.version != 0xFFFFU )
571
/* we have an OS/2 table; use the `fsSelection' field */
572
if ( face->os2.fsSelection & 1 )
573
flags |= FT_STYLE_FLAG_ITALIC;
575
if ( face->os2.fsSelection & 32 )
576
flags |= FT_STYLE_FLAG_BOLD;
580
/* this is an old Mac font, use the header field */
581
if ( face->header.Mac_Style & 1 )
582
flags |= FT_STYLE_FLAG_BOLD;
584
if ( face->header.Mac_Style & 2 )
585
flags |= FT_STYLE_FLAG_ITALIC;
588
root->style_flags = flags;
590
/*********************************************************************/
592
/* Polish the charmaps. */
594
/* Try to set the charmap encoding according to the platform & */
595
/* encoding ID of each charmap. */
598
tt_face_build_cmaps( face ); /* ignore errors */
601
/* set the encoding fields */
606
for ( m = 0; m < root->num_charmaps; m++ )
608
FT_CharMap charmap = root->charmaps[m];
611
charmap->encoding = sfnt_find_encoding( charmap->platform_id,
612
charmap->encoding_id );
615
if ( root->charmap == NULL &&
616
charmap->encoding == FT_ENCODING_UNICODE )
618
/* set 'root->charmap' to the first Unicode encoding we find */
619
root->charmap = charmap;
626
#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
628
if ( face->num_sbit_strikes )
633
root->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
636
/* XXX: I don't know criteria whether layout is horizontal */
638
if ( has_outline.... )
641
root->face_flags |= FT_FACE_FLAG_VERTICAL;
644
root->num_fixed_sizes = (FT_Int)face->num_sbit_strikes;
646
if ( FT_NEW_ARRAY( root->available_sizes, face->num_sbit_strikes ) )
649
for ( n = 0 ; n < face->num_sbit_strikes ; n++ )
651
FT_Bitmap_Size* bsize = root->available_sizes + n;
652
TT_SBit_Strike strike = face->sbit_strikes + n;
653
FT_UShort fupem = face->header.Units_Per_EM;
654
FT_Short height = (FT_Short)( face->horizontal.Ascender -
655
face->horizontal.Descender +
656
face->horizontal.Line_Gap );
657
FT_Short avg = face->os2.xAvgCharWidth;
662
(FT_Short)( ( height * strike->y_ppem + fupem/2 ) / fupem );
664
(FT_Short)( ( avg * strike->y_ppem + fupem/2 ) / fupem );
665
bsize->size = strike->y_ppem << 6;
666
bsize->x_ppem = strike->x_ppem << 6;
667
bsize->y_ppem = strike->y_ppem << 6;
672
#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
675
root->num_fixed_sizes = 0;
676
root->available_sizes = 0;
679
/*********************************************************************/
681
/* Set up metrics. */
683
if ( has_outline == TRUE )
685
/* XXX What about if outline header is missing */
686
/* (e.g. sfnt wrapped bitmap)? */
687
root->bbox.xMin = face->header.xMin;
688
root->bbox.yMin = face->header.yMin;
689
root->bbox.xMax = face->header.xMax;
690
root->bbox.yMax = face->header.yMax;
691
root->units_per_EM = face->header.Units_Per_EM;
694
/* XXX: Computing the ascender/descender/height is very different */
695
/* from what the specification tells you. Apparently, we */
696
/* must be careful because */
698
/* - not all fonts have an OS/2 table; in this case, we take */
699
/* the values in the horizontal header. However, these */
700
/* values very often are not reliable. */
702
/* - otherwise, the correct typographic values are in the */
703
/* sTypoAscender, sTypoDescender & sTypoLineGap fields. */
705
/* However, certains fonts have these fields set to 0. */
706
/* Rather, they have usWinAscent & usWinDescent correctly */
707
/* set (but with different values). */
709
/* As an example, Arial Narrow is implemented through four */
710
/* files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */
712
/* Strangely, all fonts have the same values in their */
713
/* sTypoXXX fields, except ARIALNB which sets them to 0. */
715
/* On the other hand, they all have different */
716
/* usWinAscent/Descent values -- as a conclusion, the OS/2 */
717
/* table cannot be used to compute the text height reliably! */
720
/* The ascender/descender/height are computed from the OS/2 table */
721
/* when found. Otherwise, they're taken from the horizontal */
725
root->ascender = face->horizontal.Ascender;
726
root->descender = face->horizontal.Descender;
728
root->height = (FT_Short)( root->ascender - root->descender +
729
face->horizontal.Line_Gap );
732
/* if the line_gap is 0, we add an extra 15% to the text height -- */
733
/* this computation is based on various versions of Times New Roman */
734
if ( face->horizontal.Line_Gap == 0 )
735
root->height = (FT_Short)( ( root->height * 115 + 50 ) / 100 );
740
/* some fonts have the OS/2 "sTypoAscender", "sTypoDescender" & */
741
/* "sTypoLineGap" fields set to 0, like ARIALNB.TTF */
742
if ( face->os2.version != 0xFFFFU && root->ascender )
747
root->ascender = face->os2.sTypoAscender;
748
root->descender = -face->os2.sTypoDescender;
750
height = root->ascender + root->descender + face->os2.sTypoLineGap;
751
if ( height > root->height )
752
root->height = height;
757
root->max_advance_width = face->horizontal.advance_Width_Max;
759
root->max_advance_height = (FT_Short)( face->vertical_info
760
? face->vertical.advance_Height_Max
763
root->underline_position = face->postscript.underlinePosition;
764
root->underline_thickness = face->postscript.underlineThickness;
766
/* root->max_points -- already set up */
767
/* root->max_contours -- already set up */
780
sfnt_done_face( TT_Face face )
782
FT_Memory memory = face->root.memory;
783
SFNT_Service sfnt = (SFNT_Service)face->sfnt;
788
/* destroy the postscript names table if it is loaded */
789
if ( sfnt->free_psnames )
790
sfnt->free_psnames( face );
792
/* destroy the embedded bitmaps table if it is loaded */
793
if ( sfnt->free_sbits )
794
sfnt->free_sbits( face );
797
/* freeing the kerning table */
798
FT_FREE( face->kern_pairs );
799
face->num_kern_pairs = 0;
801
/* freeing the collection table */
802
FT_FREE( face->ttc_header.offsets );
803
face->ttc_header.count = 0;
805
/* freeing table directory */
806
FT_FREE( face->dir_tables );
807
face->num_tables = 0;
810
FT_Stream stream = FT_FACE_STREAM( face );
813
/* simply release the 'cmap' table frame */
814
FT_FRAME_RELEASE( face->cmap_table );
818
/* freeing the horizontal metrics */
819
FT_FREE( face->horizontal.long_metrics );
820
FT_FREE( face->horizontal.short_metrics );
822
/* freeing the vertical ones, if any */
823
if ( face->vertical_info )
825
FT_FREE( face->vertical.long_metrics );
826
FT_FREE( face->vertical.short_metrics );
827
face->vertical_info = 0;
830
/* freeing the gasp table */
831
FT_FREE( face->gasp.gaspRanges );
832
face->gasp.numRanges = 0;
834
/* freeing the name table */
835
sfnt->free_names( face );
837
/* freeing the hdmx table */
838
sfnt->free_hdmx( face );
840
/* freeing family and style name */
841
FT_FREE( face->root.family_name );
842
FT_FREE( face->root.style_name );
844
/* freeing sbit size table */
845
FT_FREE( face->root.available_sizes );
846
face->root.num_fixed_sizes = 0;
848
FT_FREE( face->postscript_name );