tt_face_load_loca( TT_Face face, FT_Stream stream ) { FT_Error error; FT_ULong table_len; /* we need the size of the `glyf' table for malformed `loca' tables */ error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len ); if ( error ) goto Exit; FT_TRACE2(( "Locations " )); error = face->goto_table( face, TTAG_loca, stream, &table_len ); if ( error ) { error = TT_Err_Locations_Missing; goto Exit; } if ( face->header.Index_To_Loc_Format != 0 ) { if ( table_len >= 0x40000L ) { FT_TRACE2(( "table too large!\n" )); error = TT_Err_Invalid_Table; goto Exit; } face->num_locations = (FT_UInt)( table_len >> 2 ); } else { if ( table_len >= 0x20000L )
tt_face_load_loca( TT_Face face, FT_Stream stream ) { FT_Error error; FT_ULong table_len; FT_Int shift; /* we need the size of the `glyf' table for malformed `loca' tables */ error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len ); /* it is possible that a font doesn't have a glyf table at all */ /* or its size is zero */ if ( FT_ERR_EQ( error, Table_Missing ) ) { face->glyf_len = 0; face->glyf_offset = 0; } else if ( error ) goto Exit; else { #ifdef FT_CONFIG_OPTION_INCREMENTAL if ( face->root.internal->incremental_interface ) face->glyf_offset = 0; else #endif face->glyf_offset = FT_STREAM_POS(); } FT_TRACE2(( "Locations " )); error = face->goto_table( face, TTAG_loca, stream, &table_len ); if ( error ) { error = FT_THROW( Locations_Missing ); goto Exit; } if ( face->header.Index_To_Loc_Format != 0 ) { shift = 2; if ( table_len >= 0x40000L ) { FT_TRACE2(( "table too large\n" )); table_len = 0x3FFFFL; } face->num_locations = table_len >> shift; }
static FT_Error load_post_names( TT_Face face ) { FT_Stream stream; FT_Error error; FT_Fixed format; /* get a stream for the face's resource */ stream = face->root.stream; /* seek to the beginning of the PS names table */ error = face->goto_table( face, TTAG_post, stream, 0 ); if ( error ) goto Exit; format = face->postscript.FormatType; /* go to beginning of subtable */ if ( FT_STREAM_SKIP( 32 ) ) goto Exit; /* now read postscript table */ if ( format == 0x00020000L ) error = load_format_20( face, stream ); else if ( format == 0x00028000L ) error = load_format_25( face, stream ); else error = SFNT_Err_Invalid_File_Format; face->postscript_names.loaded = 1; Exit: return error; }
tt_face_load_hmtx( TT_Face face, FT_Stream stream, FT_Bool vertical ) { FT_Error error; FT_ULong tag, table_size; FT_ULong* ptable_offset; FT_ULong* ptable_size; if ( vertical ) { tag = TTAG_vmtx; ptable_offset = &face->vert_metrics_offset; ptable_size = &face->vert_metrics_size; } else { tag = TTAG_hmtx; ptable_offset = &face->horz_metrics_offset; ptable_size = &face->horz_metrics_size; } error = face->goto_table( face, tag, stream, &table_size ); if ( error ) goto Fail; *ptable_size = table_size; *ptable_offset = FT_STREAM_POS(); Fail: return error; }
tt_face_load_gasp( TT_Face face, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_UInt j,num_ranges; TT_GaspRange gaspranges; /* the gasp table is optional */ error = face->goto_table( face, TTAG_gasp, stream, 0 ); if ( error ) goto Exit; if ( FT_FRAME_ENTER( 4L ) ) goto Exit; face->gasp.version = FT_GET_USHORT(); face->gasp.numRanges = FT_GET_USHORT(); FT_FRAME_EXIT(); /* only support versions 0 and 1 of the table */ if ( face->gasp.version >= 2 ) { face->gasp.numRanges = 0; error = SFNT_Err_Invalid_Table; goto Exit; } num_ranges = face->gasp.numRanges; FT_TRACE3(( "numRanges: %u\n", num_ranges )); if ( FT_QNEW_ARRAY( gaspranges, num_ranges ) || FT_FRAME_ENTER( num_ranges * 4L ) ) goto Exit; face->gasp.gaspRanges = gaspranges; for ( j = 0; j < num_ranges; j++ ) { gaspranges[j].maxPPEM = FT_GET_USHORT(); gaspranges[j].gaspFlag = FT_GET_USHORT(); FT_TRACE3(( "gaspRange %d: rangeMaxPPEM %5d, rangeGaspBehavior 0x%x\n", j, gaspranges[j].maxPPEM, gaspranges[j].gaspFlag )); } FT_FRAME_EXIT(); Exit: return error; }
static FT_Error tt_face_load_generic_header( TT_Face face, FT_Stream stream, FT_ULong tag ) { FT_Error error; TT_Header* header; static const FT_Frame_Field header_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_Header FT_FRAME_START( 54 ), FT_FRAME_ULONG ( Table_Version ), FT_FRAME_ULONG ( Font_Revision ), FT_FRAME_LONG ( CheckSum_Adjust ), FT_FRAME_LONG ( Magic_Number ), FT_FRAME_USHORT( Flags ), FT_FRAME_USHORT( Units_Per_EM ), FT_FRAME_LONG ( Created[0] ), FT_FRAME_LONG ( Created[1] ), FT_FRAME_LONG ( Modified[0] ), FT_FRAME_LONG ( Modified[1] ), FT_FRAME_SHORT ( xMin ), FT_FRAME_SHORT ( yMin ), FT_FRAME_SHORT ( xMax ), FT_FRAME_SHORT ( yMax ), FT_FRAME_USHORT( Mac_Style ), FT_FRAME_USHORT( Lowest_Rec_PPEM ), FT_FRAME_SHORT ( Font_Direction ), FT_FRAME_SHORT ( Index_To_Loc_Format ), FT_FRAME_SHORT ( Glyph_Data_Format ), FT_FRAME_END }; error = face->goto_table( face, tag, stream, 0 ); if ( error ) goto Exit; header = &face->header; if ( FT_STREAM_READ_FIELDS( header_fields, header ) ) goto Exit; FT_TRACE3(( "Units per EM: %4u\n", header->Units_Per_EM )); FT_TRACE3(( "IndexToLoc: %4d\n", header->Index_To_Loc_Format )); Exit: return error; }
tt_face_load_loca( TT_Face face, FT_Stream stream ) { FT_Error error; FT_ULong table_len; FT_Int shift; /* we need the size of the `glyf' table for malformed `loca' tables */ error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len ); /* it is possible that a font doesn't have a glyf table at all */ /* or its size is zero */ if ( FT_ERR_EQ( error, Table_Missing ) ) face->glyf_len = 0; else if ( error ) goto Exit; FT_TRACE2(( "Locations " )); error = face->goto_table( face, TTAG_loca, stream, &table_len ); if ( error ) { error = FT_THROW( Locations_Missing ); goto Exit; } if ( face->header.Index_To_Loc_Format != 0 ) { shift = 2; if ( table_len >= 0x40000L ) { FT_TRACE2(( "table too large\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } face->num_locations = table_len >> shift; }
tt_face_load_hmtx( TT_Face face, FT_Stream stream, FT_Bool vertical ) { FT_Error error; FT_ULong table_size; FT_Byte** ptable; FT_ULong* ptable_size; if ( vertical ) { error = face->goto_table( face, TTAG_vmtx, stream, &table_size ); if ( error ) goto Fail; ptable = &face->vert_metrics; ptable_size = &face->vert_metrics_size; } else { error = face->goto_table( face, TTAG_hmtx, stream, &table_size ); if ( error ) goto Fail; ptable = &face->horz_metrics; ptable_size = &face->horz_metrics_size; } if ( FT_FRAME_EXTRACT( table_size, *ptable ) ) goto Fail; *ptable_size = table_size; Fail: return error; }
tt_face_load_cmap( TT_Face face, FT_Stream stream ) { FT_Error error; error = face->goto_table( face, TTAG_cmap, stream, &face->cmap_size ); if ( error ) goto Exit; if ( FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) ) face->cmap_size = 0; Exit: return error; }
FT_LOCAL_DEF FT_Error TT_Load_Locations( TT_Face face, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_Short LongOffsets; FT_ULong table_len; FT_TRACE2(( "Locations " )); LongOffsets = face->header.Index_To_Loc_Format; error = face->goto_table( face, TTAG_loca, stream, &table_len ); if ( error ) { error = TT_Err_Locations_Missing; goto Exit; } if ( LongOffsets != 0 ) { face->num_locations = (FT_UShort)( table_len >> 2 ); FT_TRACE2(( "(32bit offsets): %12d ", face->num_locations )); if ( ALLOC_ARRAY( face->glyph_locations, face->num_locations, FT_Long ) ) goto Exit; if ( ACCESS_Frame( face->num_locations * 4L ) ) goto Exit; { FT_Long* loc = face->glyph_locations; FT_Long* limit = loc + face->num_locations; for ( ; loc < limit; loc++ ) *loc = GET_Long(); } FORGET_Frame(); }
static FT_Error Load_Post_Names( TT_Face face ) { FT_Stream stream; FT_Error error; FT_Fixed format; /* get a stream for the face's resource */ stream = face->root.stream; /* seek to the beginning of the PS names table */ error = face->goto_table( face, TTAG_post, stream, 0 ); if ( error ) goto Exit; format = face->postscript.FormatType; /* go to beginning of subtable */ if ( FILE_Skip( 32 ) ) goto Exit; /* now read postscript table */ switch ( format ) { case 0x00020000L: error = Load_Format_20( face, stream ); break; case 0x00028000L: error = Load_Format_25( face, stream ); break; default: error = TT_Err_Invalid_File_Format; } face->postscript_names.loaded = 1; Exit: return error; }
tt_face_load_pclt( TT_Face face, FT_Stream stream ) { static const FT_Frame_Field pclt_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_PCLT FT_FRAME_START( 54 ), FT_FRAME_ULONG ( Version ), FT_FRAME_ULONG ( FontNumber ), FT_FRAME_USHORT( Pitch ), FT_FRAME_USHORT( xHeight ), FT_FRAME_USHORT( Style ), FT_FRAME_USHORT( TypeFamily ), FT_FRAME_USHORT( CapHeight ), FT_FRAME_BYTES ( TypeFace, 16 ), FT_FRAME_BYTES ( CharacterComplement, 8 ), FT_FRAME_BYTES ( FileName, 6 ), FT_FRAME_CHAR ( StrokeWeight ), FT_FRAME_CHAR ( WidthType ), FT_FRAME_BYTE ( SerifStyle ), FT_FRAME_BYTE ( Reserved ), FT_FRAME_END }; FT_Error error; TT_PCLT* pclt = &face->pclt; /* optional table */ error = face->goto_table( face, TTAG_PCLT, stream, 0 ); if ( error ) goto Exit; if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) ) goto Exit; Exit: return error; }
tt_face_load_post( TT_Face face, FT_Stream stream ) { FT_Error error; TT_Postscript* post = &face->postscript; static const FT_Frame_Field post_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_Postscript FT_FRAME_START( 32 ), FT_FRAME_ULONG( FormatType ), FT_FRAME_ULONG( italicAngle ), FT_FRAME_SHORT( underlinePosition ), FT_FRAME_SHORT( underlineThickness ), FT_FRAME_ULONG( isFixedPitch ), FT_FRAME_ULONG( minMemType42 ), FT_FRAME_ULONG( maxMemType42 ), FT_FRAME_ULONG( minMemType1 ), FT_FRAME_ULONG( maxMemType1 ), FT_FRAME_END }; error = face->goto_table( face, TTAG_post, stream, 0 ); if ( error ) return error; if ( FT_STREAM_READ_FIELDS( post_fields, post ) ) return error; /* we don't load the glyph names, we do that in another */ /* module (ttpost). */ FT_TRACE3(( "FormatType: 0x%x\n", post->FormatType )); FT_TRACE3(( "isFixedPitch: %s\n", post->isFixedPitch ? " yes" : " no" )); return SFNT_Err_Ok; }
static FT_ULong tt_get_sfnt_checksum( TT_Face face, FT_UShort i ) { #if 0 /* if we believe the written value, use following part. */ if ( face->dir_tables[i].CheckSum ) return face->dir_tables[i].CheckSum; #endif if ( !face->goto_table ) return 0; if ( face->goto_table( face, face->dir_tables[i].Tag, face->root.stream, NULL ) ) return 0; return (FT_ULong)tt_synth_sfnt_checksum( face->root.stream, face->dir_tables[i].Length ); }
sfnt_load_face( FT_Stream stream, TT_Face face, FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { FT_Error error; #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES FT_Error psnames_error; #endif FT_Bool has_outline; FT_Bool is_apple_sbit; FT_Bool is_apple_sbix; FT_Bool ignore_preferred_family = FALSE; FT_Bool ignore_preferred_subfamily = FALSE; SFNT_Service sfnt = (SFNT_Service)face->sfnt; FT_UNUSED( face_index ); /* Check parameters */ { FT_Int i; for ( i = 0; i < num_params; i++ ) { if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY ) ignore_preferred_family = TRUE; else if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY ) ignore_preferred_subfamily = TRUE; } } /* Load tables */ /* We now support two SFNT-based bitmapped font formats. They */ /* are recognized easily as they do not include a `glyf' */ /* table. */ /* */ /* The first format comes from Apple, and uses a table named */ /* `bhed' instead of `head' to store the font header (using */ /* the same format). It also doesn't include horizontal and */ /* vertical metrics tables (i.e. `hhea' and `vhea' tables are */ /* missing). */ /* */ /* The other format comes from Microsoft, and is used with */ /* WinCE/PocketPC. It looks like a standard TTF, except that */ /* it doesn't contain outlines. */ /* */ FT_TRACE2(( "sfnt_load_face: %08p\n\n", face )); /* do we have outlines in there? */ #ifdef FT_CONFIG_OPTION_INCREMENTAL has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 || tt_face_lookup_table( face, TTAG_glyf ) != 0 || tt_face_lookup_table( face, TTAG_CFF ) != 0 ); #else has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 || tt_face_lookup_table( face, TTAG_CFF ) != 0 ); #endif is_apple_sbit = 0; is_apple_sbix = !face->goto_table( face, TTAG_sbix, stream, 0 ); /* Apple 'sbix' color bitmaps are rendered scaled and then the 'glyf' * outline rendered on top. We don't support that yet, so just ignore * the 'glyf' outline and advertise it as a bitmap-only font. */ if ( is_apple_sbix ) has_outline = FALSE; /* if this font doesn't contain outlines, we try to load */ /* a `bhed' table */ if ( !has_outline && sfnt->load_bhed ) { LOAD_( bhed ); is_apple_sbit = FT_BOOL( !error ); } /* load the font header (`head' table) if this isn't an Apple */ /* sbit font file */ if ( !is_apple_sbit || is_apple_sbix ) { LOAD_( head ); if ( error ) goto Exit; } if ( face->header.Units_Per_EM == 0 ) { error = FT_THROW( Invalid_Table ); goto Exit; } /* the following tables are often not present in embedded TrueType */ /* fonts within PDF documents, so don't check for them. */ LOAD_( maxp ); LOAD_( cmap ); /* the following tables are optional in PCL fonts -- */ /* don't check for errors */ LOAD_( name ); LOAD_( post ); #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES psnames_error = error; #endif /* do not load the metrics headers and tables if this is an Apple */ /* sbit font file */ if ( !is_apple_sbit ) { /* load the `hhea' and `hmtx' tables */ LOADM_( hhea, 0 ); if ( !error ) { LOADM_( hmtx, 0 ); if ( FT_ERR_EQ( error, Table_Missing ) ) { error = FT_THROW( Hmtx_Table_Missing ); #ifdef FT_CONFIG_OPTION_INCREMENTAL /* If this is an incrementally loaded font and there are */ /* overriding metrics, tolerate a missing `hmtx' table. */ if ( face->root.internal->incremental_interface && face->root.internal->incremental_interface->funcs-> get_glyph_metrics ) { face->horizontal.number_Of_HMetrics = 0; error = FT_Err_Ok; } #endif } } else if ( FT_ERR_EQ( error, Table_Missing ) ) { /* No `hhea' table necessary for SFNT Mac fonts. */ if ( face->format_tag == TTAG_true ) { FT_TRACE2(( "This is an SFNT Mac font.\n" )); has_outline = 0; error = FT_Err_Ok; } else { error = FT_THROW( Horiz_Header_Missing ); #ifdef FT_CONFIG_OPTION_INCREMENTAL /* If this is an incrementally loaded font and there are */ /* overriding metrics, tolerate a missing `hhea' table. */ if ( face->root.internal->incremental_interface && face->root.internal->incremental_interface->funcs-> get_glyph_metrics ) { face->horizontal.number_Of_HMetrics = 0; error = FT_Err_Ok; } #endif } } if ( error ) goto Exit; /* try to load the `vhea' and `vmtx' tables */ LOADM_( hhea, 1 ); if ( !error ) { LOADM_( hmtx, 1 ); if ( !error ) face->vertical_info = 1; } if ( error && FT_ERR_NEQ( error, Table_Missing ) ) goto Exit; LOAD_( os2 ); if ( error ) { /* we treat the table as missing if there are any errors */ face->os2.version = 0xFFFFU; } } /* the optional tables */ /* embedded bitmap support */ if ( sfnt->load_eblc ) { LOAD_( eblc ); if ( error ) { /* a font which contains neither bitmaps nor outlines is */ /* still valid (although rather useless in most cases); */ /* however, you can find such stripped fonts in PDFs */ if ( FT_ERR_EQ( error, Table_Missing ) ) error = FT_Err_Ok; else goto Exit; } } LOAD_( pclt ); if ( error ) { if ( FT_ERR_NEQ( error, Table_Missing ) ) goto Exit; face->pclt.Version = 0; } /* consider the kerning and gasp tables as optional */ LOAD_( gasp ); LOAD_( kern ); face->root.num_glyphs = face->max_profile.numGlyphs; /* Bit 8 of the `fsSelection' field in the `OS/2' table denotes */ /* a WWS-only font face. `WWS' stands for `weight', width', and */ /* `slope', a term used by Microsoft's Windows Presentation */ /* Foundation (WPF). This flag has been introduced in version */ /* 1.5 of the OpenType specification (May 2008). */ face->root.family_name = NULL; face->root.style_name = NULL; if ( face->os2.version != 0xFFFFU && face->os2.fsSelection & 256 ) { if ( !ignore_preferred_family ) GET_NAME( PREFERRED_FAMILY, &face->root.family_name ); if ( !face->root.family_name ) GET_NAME( FONT_FAMILY, &face->root.family_name ); if ( !ignore_preferred_subfamily ) GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name ); if ( !face->root.style_name ) GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); } else { GET_NAME( WWS_FAMILY, &face->root.family_name ); if ( !face->root.family_name && !ignore_preferred_family ) GET_NAME( PREFERRED_FAMILY, &face->root.family_name ); if ( !face->root.family_name ) GET_NAME( FONT_FAMILY, &face->root.family_name ); GET_NAME( WWS_SUBFAMILY, &face->root.style_name ); if ( !face->root.style_name && !ignore_preferred_subfamily ) GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name ); if ( !face->root.style_name ) GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); } /* now set up root fields */ { FT_Face root = &face->root; FT_Long flags = root->face_flags; /*********************************************************************/ /* */ /* Compute face flags. */ /* */ if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_CBLC || face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX ) flags |= FT_FACE_FLAG_COLOR; /* color glyphs */ if ( has_outline == TRUE ) flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ /* The sfnt driver only supports bitmap fonts natively, thus we */ /* don't set FT_FACE_FLAG_HINTER. */ flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */ FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES if ( !psnames_error && face->postscript.FormatType != 0x00030000L ) flags |= FT_FACE_FLAG_GLYPH_NAMES; #endif /* fixed width font? */ if ( face->postscript.isFixedPitch ) flags |= FT_FACE_FLAG_FIXED_WIDTH; /* vertical information? */ if ( face->vertical_info ) flags |= FT_FACE_FLAG_VERTICAL; /* kerning available ? */ if ( TT_FACE_HAS_KERNING( face ) ) flags |= FT_FACE_FLAG_KERNING; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT /* Don't bother to load the tables unless somebody asks for them. */ /* No need to do work which will (probably) not be used. */ if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 && tt_face_lookup_table( face, TTAG_fvar ) != 0 && tt_face_lookup_table( face, TTAG_gvar ) != 0 ) flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; #endif root->face_flags = flags; /*********************************************************************/ /* */ /* Compute style flags. */ /* */ flags = 0; if ( has_outline == TRUE && face->os2.version != 0xFFFFU ) { /* We have an OS/2 table; use the `fsSelection' field. Bit 9 */ /* indicates an oblique font face. This flag has been */ /* introduced in version 1.5 of the OpenType specification. */ if ( face->os2.fsSelection & 512 ) /* bit 9 */ flags |= FT_STYLE_FLAG_ITALIC; else if ( face->os2.fsSelection & 1 ) /* bit 0 */ flags |= FT_STYLE_FLAG_ITALIC; if ( face->os2.fsSelection & 32 ) /* bit 5 */ flags |= FT_STYLE_FLAG_BOLD; } else { /* this is an old Mac font, use the header field */ if ( face->header.Mac_Style & 1 ) flags |= FT_STYLE_FLAG_BOLD; if ( face->header.Mac_Style & 2 ) flags |= FT_STYLE_FLAG_ITALIC; } root->style_flags = flags; /*********************************************************************/ /* */ /* Polish the charmaps. */ /* */ /* Try to set the charmap encoding according to the platform & */ /* encoding ID of each charmap. */ /* */ tt_face_build_cmaps( face ); /* ignore errors */ /* set the encoding fields */ { FT_Int m; for ( m = 0; m < root->num_charmaps; m++ ) { FT_CharMap charmap = root->charmaps[m]; charmap->encoding = sfnt_find_encoding( charmap->platform_id, charmap->encoding_id ); #if 0 if ( root->charmap == NULL && charmap->encoding == FT_ENCODING_UNICODE ) { /* set 'root->charmap' to the first Unicode encoding we find */ root->charmap = charmap; } #endif } } #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /* * Now allocate the root array of FT_Bitmap_Size records and * populate them. Unfortunately, it isn't possible to indicate bit * depths in the FT_Bitmap_Size record. This is a design error. */ { FT_UInt i, count; count = face->sbit_num_strikes; if ( count > 0 ) { FT_Memory memory = face->root.stream->memory; FT_UShort em_size = face->header.Units_Per_EM; FT_Short avgwidth = face->os2.xAvgCharWidth; FT_Size_Metrics metrics; if ( em_size == 0 || face->os2.version == 0xFFFFU ) { avgwidth = 1; em_size = 1; } if ( FT_NEW_ARRAY( root->available_sizes, count ) ) goto Exit; for ( i = 0; i < count; i++ ) { FT_Bitmap_Size* bsize = root->available_sizes + i; error = sfnt->load_strike_metrics( face, i, &metrics ); if ( error ) goto Exit; bsize->height = (FT_Short)( metrics.height >> 6 ); bsize->width = (FT_Short)( ( avgwidth * metrics.x_ppem + em_size / 2 ) / em_size ); bsize->x_ppem = metrics.x_ppem << 6; bsize->y_ppem = metrics.y_ppem << 6; /* assume 72dpi */ bsize->size = metrics.y_ppem << 6; } root->face_flags |= FT_FACE_FLAG_FIXED_SIZES; root->num_fixed_sizes = (FT_Int)count; } } #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ /* a font with no bitmaps and no outlines is scalable; */ /* it has only empty glyphs then */ if ( !FT_HAS_FIXED_SIZES( root ) && !FT_IS_SCALABLE( root ) ) root->face_flags |= FT_FACE_FLAG_SCALABLE; /*********************************************************************/ /* */ /* Set up metrics. */ /* */ if ( FT_IS_SCALABLE( root ) ) { /* XXX What about if outline header is missing */ /* (e.g. sfnt wrapped bitmap)? */ root->bbox.xMin = face->header.xMin; root->bbox.yMin = face->header.yMin; root->bbox.xMax = face->header.xMax; root->bbox.yMax = face->header.yMax; root->units_per_EM = face->header.Units_Per_EM; /* XXX: Computing the ascender/descender/height is very different */ /* from what the specification tells you. Apparently, we */ /* must be careful because */ /* */ /* - not all fonts have an OS/2 table; in this case, we take */ /* the values in the horizontal header. However, these */ /* values very often are not reliable. */ /* */ /* - otherwise, the correct typographic values are in the */ /* sTypoAscender, sTypoDescender & sTypoLineGap fields. */ /* */ /* However, certain fonts have these fields set to 0. */ /* Rather, they have usWinAscent & usWinDescent correctly */ /* set (but with different values). */ /* */ /* As an example, Arial Narrow is implemented through four */ /* files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */ /* */ /* Strangely, all fonts have the same values in their */ /* sTypoXXX fields, except ARIALNB which sets them to 0. */ /* */ /* On the other hand, they all have different */ /* usWinAscent/Descent values -- as a conclusion, the OS/2 */ /* table cannot be used to compute the text height reliably! */ /* */ /* The ascender and descender are taken from the `hhea' table. */ /* If zero, they are taken from the `OS/2' table. */ root->ascender = face->horizontal.Ascender; root->descender = face->horizontal.Descender; root->height = root->ascender - root->descender + face->horizontal.Line_Gap; if ( !( root->ascender || root->descender ) ) { if ( face->os2.version != 0xFFFFU ) { if ( face->os2.sTypoAscender || face->os2.sTypoDescender ) { root->ascender = face->os2.sTypoAscender; root->descender = face->os2.sTypoDescender; root->height = root->ascender - root->descender + face->os2.sTypoLineGap; } else { root->ascender = (FT_Short)face->os2.usWinAscent; root->descender = -(FT_Short)face->os2.usWinDescent; root->height = root->ascender - root->descender; } } } root->max_advance_width = (FT_Short)face->horizontal.advance_Width_Max; root->max_advance_height = (FT_Short)( face->vertical_info ? face->vertical.advance_Height_Max : root->height ); /* See http://www.microsoft.com/OpenType/OTSpec/post.htm -- */ /* Adjust underline position from top edge to centre of */ /* stroke to convert TrueType meaning to FreeType meaning. */ root->underline_position = face->postscript.underlinePosition - face->postscript.underlineThickness / 2; root->underline_thickness = face->postscript.underlineThickness; } }
tt_face_load_hhea( TT_Face face, FT_Stream stream, FT_Bool vertical ) { FT_Error error; TT_HoriHeader* header; const FT_Frame_Field metrics_header_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_HoriHeader FT_FRAME_START( 36 ), FT_FRAME_ULONG ( Version ), FT_FRAME_SHORT ( Ascender ), FT_FRAME_SHORT ( Descender ), FT_FRAME_SHORT ( Line_Gap ), FT_FRAME_USHORT( advance_Width_Max ), FT_FRAME_SHORT ( min_Left_Side_Bearing ), FT_FRAME_SHORT ( min_Right_Side_Bearing ), FT_FRAME_SHORT ( xMax_Extent ), FT_FRAME_SHORT ( caret_Slope_Rise ), FT_FRAME_SHORT ( caret_Slope_Run ), FT_FRAME_SHORT ( caret_Offset ), FT_FRAME_SHORT ( Reserved[0] ), FT_FRAME_SHORT ( Reserved[1] ), FT_FRAME_SHORT ( Reserved[2] ), FT_FRAME_SHORT ( Reserved[3] ), FT_FRAME_SHORT ( metric_Data_Format ), FT_FRAME_USHORT( number_Of_HMetrics ), FT_FRAME_END }; if ( vertical ) { void *v = &face->vertical; error = face->goto_table( face, TTAG_vhea, stream, 0 ); if ( error ) goto Fail; header = (TT_HoriHeader*)v; } else { error = face->goto_table( face, TTAG_hhea, stream, 0 ); if ( error ) goto Fail; header = &face->horizontal; } if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) ) goto Fail; FT_TRACE3(( "Ascender: %5d\n", header->Ascender )); FT_TRACE3(( "Descender: %5d\n", header->Descender )); FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics )); header->long_metrics = NULL; header->short_metrics = NULL; Fail: return error; }
tt_face_load_hmtx( TT_Face face, FT_Stream stream, FT_Bool vertical ) { FT_Error error; FT_Memory memory = stream->memory; FT_ULong table_len; FT_Long num_shorts, num_longs, num_shorts_checked; TT_LongMetrics* longs; TT_ShortMetrics** shorts; FT_Byte* p; if ( vertical ) { void* lm = &face->vertical.long_metrics; void** sm = &face->vertical.short_metrics; error = face->goto_table( face, TTAG_vmtx, stream, &table_len ); if ( error ) goto Fail; num_longs = face->vertical.number_Of_VMetrics; if ( (FT_ULong)num_longs > table_len / 4 ) num_longs = (FT_Long)( table_len / 4 ); face->vertical.number_Of_VMetrics = 0; longs = (TT_LongMetrics*)lm; shorts = (TT_ShortMetrics**)sm; } else { void* lm = &face->horizontal.long_metrics; void** sm = &face->horizontal.short_metrics; error = face->goto_table( face, TTAG_hmtx, stream, &table_len ); if ( error ) goto Fail; num_longs = face->horizontal.number_Of_HMetrics; if ( (FT_ULong)num_longs > table_len / 4 ) num_longs = (FT_Long)( table_len / 4 ); face->horizontal.number_Of_HMetrics = 0; longs = (TT_LongMetrics*)lm; shorts = (TT_ShortMetrics**)sm; } /* never trust derived values */ num_shorts = face->max_profile.numGlyphs - num_longs; num_shorts_checked = ( table_len - num_longs * 4L ) / 2; if ( num_shorts < 0 ) { FT_ERROR(( "%cmtx has more metrics than glyphs.\n" )); /* Adobe simply ignores this problem. So we shall do the same. */ #if 0 error = vertical ? SFNT_Err_Invalid_Vert_Metrics : SFNT_Err_Invalid_Horiz_Metrics; goto Exit; #else num_shorts = 0; #endif } if ( FT_QNEW_ARRAY( *longs, num_longs ) || FT_QNEW_ARRAY( *shorts, num_shorts ) ) goto Fail; if ( FT_FRAME_ENTER( table_len ) ) goto Fail; p = stream->cursor; { TT_LongMetrics cur = *longs; TT_LongMetrics limit = cur + num_longs; for ( ; cur < limit; cur++ ) { cur->advance = FT_NEXT_USHORT( p ); cur->bearing = FT_NEXT_SHORT( p ); } } /* do we have an inconsistent number of metric values? */ { TT_ShortMetrics* cur = *shorts; TT_ShortMetrics* limit = cur + FT_MIN( num_shorts, num_shorts_checked ); for ( ; cur < limit; cur++ ) *cur = FT_NEXT_SHORT( p ); /* We fill up the missing left side bearings with the */ /* last valid value. Since this will occur for buggy CJK */ /* fonts usually only, nothing serious will happen. */ if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 ) { FT_Short val = (*shorts)[num_shorts_checked - 1]; limit = *shorts + num_shorts; for ( ; cur < limit; cur++ ) *cur = val; } } FT_FRAME_EXIT(); if ( vertical ) face->vertical.number_Of_VMetrics = (FT_UShort)num_longs; else face->horizontal.number_Of_HMetrics = (FT_UShort)num_longs; Fail: return error; }
tt_face_load_kern( TT_Face face, FT_Stream stream ) { FT_Error error; FT_ULong table_size; FT_Byte* p; FT_Byte* p_limit; FT_UInt nn, num_tables; FT_UInt32 avail = 0, ordered = 0; /* the kern table is optional; exit silently if it is missing */ error = face->goto_table( face, TTAG_kern, stream, &table_size ); if ( error ) goto Exit; if ( table_size < 4 ) /* the case of a malformed table */ { FT_ERROR(( "tt_face_load_kern:" " kerning table is too small - ignored\n" )); error = FT_THROW( Table_Missing ); goto Exit; } if ( FT_FRAME_EXTRACT( table_size, face->kern_table ) ) { FT_ERROR(( "tt_face_load_kern:" " could not extract kerning table\n" )); goto Exit; } face->kern_table_size = table_size; p = face->kern_table; p_limit = p + table_size; p += 2; /* skip version */ num_tables = FT_NEXT_USHORT( p ); if ( num_tables > 32 ) /* we only support up to 32 sub-tables */ num_tables = 32; for ( nn = 0; nn < num_tables; nn++ ) { FT_UInt num_pairs, length, coverage; FT_Byte* p_next; FT_UInt32 mask = (FT_UInt32)1UL << nn; if ( p + 6 > p_limit ) break; p_next = p; p += 2; /* skip version */ length = FT_NEXT_USHORT( p ); coverage = FT_NEXT_USHORT( p ); if ( length <= 6 ) break; p_next += length; if ( p_next > p_limit ) /* handle broken table */ p_next = p_limit; /* only use horizontal kerning tables */ if ( ( coverage & ~8 ) != 0x0001 || p + 8 > p_limit ) goto NextTable; num_pairs = FT_NEXT_USHORT( p ); p += 6; if ( ( p_next - p ) < 6 * (int)num_pairs ) /* handle broken count */ num_pairs = (FT_UInt)( ( p_next - p ) / 6 ); avail |= mask; /* * Now check whether the pairs in this table are ordered. * We then can use binary search. */ if ( num_pairs > 0 ) { FT_ULong count; FT_ULong old_pair; old_pair = FT_NEXT_ULONG( p ); p += 2; for ( count = num_pairs - 1; count > 0; count-- ) { FT_UInt32 cur_pair; cur_pair = FT_NEXT_ULONG( p ); if ( cur_pair <= old_pair ) break; p += 2; old_pair = cur_pair; } if ( count == 0 ) ordered |= mask; } NextTable: p = p_next; } face->num_kern_tables = nn; face->kern_avail_bits = avail; face->kern_order_bits = ordered; Exit: return error; }
tt_face_load_os2( TT_Face face, FT_Stream stream ) { FT_Error error; TT_OS2* os2; const FT_Frame_Field os2_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_OS2 FT_FRAME_START( 78 ), FT_FRAME_USHORT( version ), FT_FRAME_SHORT ( xAvgCharWidth ), FT_FRAME_USHORT( usWeightClass ), FT_FRAME_USHORT( usWidthClass ), FT_FRAME_SHORT ( fsType ), FT_FRAME_SHORT ( ySubscriptXSize ), FT_FRAME_SHORT ( ySubscriptYSize ), FT_FRAME_SHORT ( ySubscriptXOffset ), FT_FRAME_SHORT ( ySubscriptYOffset ), FT_FRAME_SHORT ( ySuperscriptXSize ), FT_FRAME_SHORT ( ySuperscriptYSize ), FT_FRAME_SHORT ( ySuperscriptXOffset ), FT_FRAME_SHORT ( ySuperscriptYOffset ), FT_FRAME_SHORT ( yStrikeoutSize ), FT_FRAME_SHORT ( yStrikeoutPosition ), FT_FRAME_SHORT ( sFamilyClass ), FT_FRAME_BYTE ( panose[0] ), FT_FRAME_BYTE ( panose[1] ), FT_FRAME_BYTE ( panose[2] ), FT_FRAME_BYTE ( panose[3] ), FT_FRAME_BYTE ( panose[4] ), FT_FRAME_BYTE ( panose[5] ), FT_FRAME_BYTE ( panose[6] ), FT_FRAME_BYTE ( panose[7] ), FT_FRAME_BYTE ( panose[8] ), FT_FRAME_BYTE ( panose[9] ), FT_FRAME_ULONG ( ulUnicodeRange1 ), FT_FRAME_ULONG ( ulUnicodeRange2 ), FT_FRAME_ULONG ( ulUnicodeRange3 ), FT_FRAME_ULONG ( ulUnicodeRange4 ), FT_FRAME_BYTE ( achVendID[0] ), FT_FRAME_BYTE ( achVendID[1] ), FT_FRAME_BYTE ( achVendID[2] ), FT_FRAME_BYTE ( achVendID[3] ), FT_FRAME_USHORT( fsSelection ), FT_FRAME_USHORT( usFirstCharIndex ), FT_FRAME_USHORT( usLastCharIndex ), FT_FRAME_SHORT ( sTypoAscender ), FT_FRAME_SHORT ( sTypoDescender ), FT_FRAME_SHORT ( sTypoLineGap ), FT_FRAME_USHORT( usWinAscent ), FT_FRAME_USHORT( usWinDescent ), FT_FRAME_END }; const FT_Frame_Field os2_fields_extra[] = { FT_FRAME_START( 8 ), FT_FRAME_ULONG( ulCodePageRange1 ), FT_FRAME_ULONG( ulCodePageRange2 ), FT_FRAME_END }; const FT_Frame_Field os2_fields_extra2[] = { FT_FRAME_START( 10 ), FT_FRAME_SHORT ( sxHeight ), FT_FRAME_SHORT ( sCapHeight ), FT_FRAME_USHORT( usDefaultChar ), FT_FRAME_USHORT( usBreakChar ), FT_FRAME_USHORT( usMaxContext ), FT_FRAME_END }; /* We now support old Mac fonts where the OS/2 table doesn't */ /* exist. Simply put, we set the `version' field to 0xFFFF */ /* and test this value each time we need to access the table. */ error = face->goto_table( face, TTAG_OS2, stream, 0 ); if ( error ) goto Exit; os2 = &face->os2; if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) ) goto Exit; os2->ulCodePageRange1 = 0; os2->ulCodePageRange2 = 0; os2->sxHeight = 0; os2->sCapHeight = 0; os2->usDefaultChar = 0; os2->usBreakChar = 0; os2->usMaxContext = 0; if ( os2->version >= 0x0001 ) { /* only version 1 tables */ if ( FT_STREAM_READ_FIELDS( os2_fields_extra, os2 ) ) goto Exit; if ( os2->version >= 0x0002 ) { /* only version 2 tables */ if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) ) goto Exit; } } FT_TRACE3(( "sTypoAscender: %4d\n", os2->sTypoAscender )); FT_TRACE3(( "sTypoDescender: %4d\n", os2->sTypoDescender )); FT_TRACE3(( "usWinAscent: %4u\n", os2->usWinAscent )); FT_TRACE3(( "usWinDescent: %4u\n", os2->usWinDescent )); FT_TRACE3(( "fsSelection: 0x%2x\n", os2->fsSelection )); Exit: return error; }
tt_face_load_name( TT_Face face, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_ULong table_pos, table_len; FT_ULong storage_start, storage_limit; FT_UInt count; TT_NameTable table; static const FT_Frame_Field name_table_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_NameTableRec FT_FRAME_START( 6 ), FT_FRAME_USHORT( format ), FT_FRAME_USHORT( numNameRecords ), FT_FRAME_USHORT( storageOffset ), FT_FRAME_END }; static const FT_Frame_Field name_record_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_NameEntryRec /* no FT_FRAME_START */ FT_FRAME_USHORT( platformID ), FT_FRAME_USHORT( encodingID ), FT_FRAME_USHORT( languageID ), FT_FRAME_USHORT( nameID ), FT_FRAME_USHORT( stringLength ), FT_FRAME_USHORT( stringOffset ), FT_FRAME_END }; table = &face->name_table; table->stream = stream; error = face->goto_table( face, TTAG_name, stream, &table_len ); if ( error ) goto Exit; table_pos = FT_STREAM_POS(); if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) ) goto Exit; /* Some popular Asian fonts have an invalid `storageOffset' value */ /* (it should be at least "6 + 12*num_names"). However, the string */ /* offsets, computed as "storageOffset + entry->stringOffset", are */ /* valid pointers within the name table... */ /* */ /* We thus can't check `storageOffset' right now. */ /* */ storage_start = table_pos + 6 + 12*table->numNameRecords; storage_limit = table_pos + table_len; if ( storage_start > storage_limit ) { FT_ERROR(( "tt_face_load_name: invalid `name' table\n" )); error = SFNT_Err_Name_Table_Missing; goto Exit; } /* Allocate the array of name records. */ count = table->numNameRecords; table->numNameRecords = 0; if ( FT_NEW_ARRAY( table->names, count ) || FT_FRAME_ENTER( count * 12 ) ) goto Exit; /* Load the name records and determine how much storage is needed */ /* to hold the strings themselves. */ { TT_NameEntryRec* entry = table->names; for ( ; count > 0; count-- ) { if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) ) continue; /* check that the name is not empty */ if ( entry->stringLength == 0 ) continue; /* check that the name string is within the table */ entry->stringOffset += table_pos + table->storageOffset; if ( entry->stringOffset < storage_start || entry->stringOffset + entry->stringLength > storage_limit ) { /* invalid entry - ignore it */ entry->stringOffset = 0; entry->stringLength = 0; continue; } entry++; } table->numNameRecords = (FT_UInt)( entry - table->names ); } FT_FRAME_EXIT(); /* everything went well, update face->num_names */ face->num_names = (FT_UShort) table->numNameRecords; Exit: return error; }
tt_face_load_maxp( TT_Face face, FT_Stream stream ) { FT_Error error; TT_MaxProfile* maxProfile = &face->max_profile; const FT_Frame_Field maxp_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_MaxProfile FT_FRAME_START( 6 ), FT_FRAME_LONG ( version ), FT_FRAME_USHORT( numGlyphs ), FT_FRAME_END }; const FT_Frame_Field maxp_fields_extra[] = { FT_FRAME_START( 26 ), FT_FRAME_USHORT( maxPoints ), FT_FRAME_USHORT( maxContours ), FT_FRAME_USHORT( maxCompositePoints ), FT_FRAME_USHORT( maxCompositeContours ), FT_FRAME_USHORT( maxZones ), FT_FRAME_USHORT( maxTwilightPoints ), FT_FRAME_USHORT( maxStorage ), FT_FRAME_USHORT( maxFunctionDefs ), FT_FRAME_USHORT( maxInstructionDefs ), FT_FRAME_USHORT( maxStackElements ), FT_FRAME_USHORT( maxSizeOfInstructions ), FT_FRAME_USHORT( maxComponentElements ), FT_FRAME_USHORT( maxComponentDepth ), FT_FRAME_END }; error = face->goto_table( face, TTAG_maxp, stream, 0 ); if ( error ) goto Exit; if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) ) goto Exit; maxProfile->maxPoints = 0; maxProfile->maxContours = 0; maxProfile->maxCompositePoints = 0; maxProfile->maxCompositeContours = 0; maxProfile->maxZones = 0; maxProfile->maxTwilightPoints = 0; maxProfile->maxStorage = 0; maxProfile->maxFunctionDefs = 0; maxProfile->maxInstructionDefs = 0; maxProfile->maxStackElements = 0; maxProfile->maxSizeOfInstructions = 0; maxProfile->maxComponentElements = 0; maxProfile->maxComponentDepth = 0; if ( maxProfile->version >= 0x10000L ) { if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) ) goto Exit; /* XXX: an adjustment that is necessary to load certain */ /* broken fonts like `Keystrokes MT' :-( */ /* */ /* We allocate 64 function entries by default when */ /* the maxFunctionDefs field is null. */ if ( maxProfile->maxFunctionDefs == 0 ) maxProfile->maxFunctionDefs = 64; /* we add 4 phantom points later */ if ( maxProfile->maxTwilightPoints > ( 0xFFFFU - 4 ) ) { FT_TRACE0(( "tt_face_load_maxp:" " too much twilight points in `maxp' table;\n" " " " some glyphs might be rendered incorrectly\n" )); maxProfile->maxTwilightPoints = 0xFFFFU - 4; } } FT_TRACE3(( "numGlyphs: %u\n", maxProfile->numGlyphs )); Exit: return error; }
tt_face_load_colr( TT_Face face, FT_Stream stream ) { FT_Error error; FT_Memory memory = face->root.memory; FT_Byte* table = NULL; FT_Byte* p = NULL; Colr* colr = NULL; FT_ULong base_glyph_offset, layer_offset; FT_ULong table_size; /* `COLR' always needs `CPAL' */ if ( !face->cpal ) return FT_THROW( Invalid_File_Format ); error = face->goto_table( face, TTAG_COLR, stream, &table_size ); if ( error ) goto NoColr; if ( table_size < COLR_HEADER_SIZE ) goto InvalidTable; if ( FT_FRAME_EXTRACT( table_size, table ) ) goto NoColr; p = table; if ( FT_NEW( colr ) ) goto NoColr; colr->version = FT_NEXT_USHORT( p ); if ( colr->version != 0 ) goto InvalidTable; colr->num_base_glyphs = FT_NEXT_USHORT( p ); base_glyph_offset = FT_NEXT_ULONG( p ); if ( base_glyph_offset >= table_size ) goto InvalidTable; if ( colr->num_base_glyphs * BASE_GLYPH_SIZE > table_size - base_glyph_offset ) goto InvalidTable; layer_offset = FT_NEXT_ULONG( p ); colr->num_layers = FT_NEXT_USHORT( p ); if ( layer_offset >= table_size ) goto InvalidTable; if ( colr->num_layers * LAYER_SIZE > table_size - layer_offset ) goto InvalidTable; colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset ); colr->layers = (FT_Byte*)( table + layer_offset ); colr->table = table; colr->table_size = table_size; face->colr = colr; return FT_Err_Ok; InvalidTable: error = FT_THROW( Invalid_Table ); NoColr: FT_FRAME_RELEASE( table ); FT_FREE( colr ); return error; }