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 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; /* 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) { LOAD_(head); if (error) goto Exit; } if (face->header.Units_Per_EM == 0) { error = SFNT_Err_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 (error == SFNT_Err_Table_Missing) { error = SFNT_Err_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 = SFNT_Err_Ok; } #endif } } else if (error == SFNT_Err_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 = SFNT_Err_Ok; } else { error = SFNT_Err_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 = SFNT_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 && error != SFNT_Err_Table_Missing) goto Exit; LOAD_(os2); if (error) { if (error != SFNT_Err_Table_Missing) goto Exit; 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 (error == SFNT_Err_Table_Missing) error = SFNT_Err_Ok; else goto Exit; } } LOAD_(pclt); if (error) { if (error != SFNT_Err_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 (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 == SFNT_Err_Ok && 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; #ifndef FT_CONFIG_OPTION_OLD_INTERNALS count = face->sbit_num_strikes; #else count = (FT_UInt)face->num_sbit_strikes; #endif 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 = 0; 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/descender/height are computed from the OS/2 table */ /* when found. Otherwise, they're taken from the horizontal */ /* header. */ /* */ root->ascender = face->horizontal.Ascender; root->descender = face->horizontal.Descender; root->height = (FT_Short)(root->ascender - root->descender + face->horizontal.Line_Gap); #if 0 /* if the line_gap is 0, we add an extra 15% to the text height -- */ /* this computation is based on various versions of Times New Roman */ if (face->horizontal.Line_Gap == 0) root->height = (FT_Short)((root->height * 115 + 50) / 100); #endif /* 0 */ #if 0 /* some fonts have the OS/2 "sTypoAscender", "sTypoDescender" & */ /* "sTypoLineGap" fields set to 0, like ARIALNB.TTF */ if (face->os2.version != 0xFFFFU && root->ascender) { FT_Int height; root->ascender = face->os2.sTypoAscender; root->descender = -face->os2.sTypoDescender; height = root->ascender + root->descender + face->os2.sTypoLineGap; if (height > root->height) root->height = height; } #endif /* 0 */ root->max_advance_width = 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; } }
sfnt_load_face( FT_Stream stream, TT_Face face, FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { FT_Error error, psnames_error; FT_Bool has_outline; FT_Bool is_apple_sbit; SFNT_Service sfnt = (SFNT_Service)face->sfnt; FT_UNUSED( face_index ); FT_UNUSED( num_params ); FT_UNUSED( params ); /* 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. */ /* */ /* 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; #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /* if this font doesn't contain outlines, we try to load */ /* a `bhed' table */ if ( !has_outline ) is_apple_sbit = FT_BOOL( !LOAD_( bitmap_header ) ); #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ /* load the font header (`head' table) if this isn't an Apple */ /* sbit font file */ if ( !is_apple_sbit && LOAD_( header ) ) goto Exit; /* the following tables are often not present in embedded TrueType */ /* fonts within PDF documents, so don't check for them. */ (void)LOAD_( max_profile ); (void)LOAD_( charmaps ); /* the following tables are optional in PCL fonts -- */ /* don't check for errors */ (void)LOAD_( names ); psnames_error = LOAD_( psnames ); /* 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 at once */ error = sfnt->load_metrics( face, stream, 0 ); if ( error ) goto Exit; /* try to load the `vhea' and `vmtx' tables at once */ error = sfnt->load_metrics( face, stream, 1 ); if ( error ) goto Exit; if ( LOAD_( os2 ) ) goto Exit; } /* the optional tables */ #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /* embedded bitmap support. */ if ( sfnt->load_sbits && LOAD_( sbits ) ) { /* return an error if this font file has no outlines */ if ( error == SFNT_Err_Table_Missing && has_outline ) error = SFNT_Err_Ok; else goto Exit; } #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ if ( LOAD_( hdmx ) || LOAD_( pclt ) ) goto Exit; /* consider the kerning and gasp tables as optional */ (void)LOAD_( gasp ); (void)LOAD_( kerning ); error = SFNT_Err_Ok; face->root.family_name = tt_face_get_name( face, TT_NAME_ID_PREFERRED_FAMILY ); if ( !face->root.family_name ) face->root.family_name = tt_face_get_name( face, TT_NAME_ID_FONT_FAMILY ); face->root.style_name = tt_face_get_name( face, TT_NAME_ID_PREFERRED_SUBFAMILY ); if ( !face->root.style_name ) face->root.style_name = tt_face_get_name( face, TT_NAME_ID_FONT_SUBFAMILY ); /* now set up root fields */ { FT_Face root = &face->root; FT_Int32 flags = root->face_flags; /*********************************************************************/ /* */ /* Compute face flags. */ /* */ if ( has_outline == TRUE ) flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */ FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES if ( psnames_error == SFNT_Err_Ok && 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; #if 0 /* kerning available ? */ if ( TT_FACE_HAS_KERNING( face ) ) flags |= FT_FACE_FLAG_KERNING; #endif #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 */ if ( face->os2.fsSelection & 1 ) flags |= FT_STYLE_FLAG_ITALIC; if ( face->os2.fsSelection & 32 ) 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 } } /*********************************************************************/ /* */ /* Set up metrics. */ /* */ if ( has_outline == TRUE ) { /* 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, certains 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/descender/height are computed from the OS/2 table */ /* when found. Otherwise, they're taken from the horizontal */ /* header. */ /* */ root->ascender = face->horizontal.Ascender; root->descender = face->horizontal.Descender; root->height = (FT_Short)( root->ascender - root->descender + face->horizontal.Line_Gap ); #if 0 /* if the line_gap is 0, we add an extra 15% to the text height -- */ /* this computation is based on various versions of Times New Roman */ if ( face->horizontal.Line_Gap == 0 ) root->height = (FT_Short)( ( root->height * 115 + 50 ) / 100 ); #endif #if 0 /* some fonts have the OS/2 "sTypoAscender", "sTypoDescender" & */ /* "sTypoLineGap" fields set to 0, like ARIALNB.TTF */ if ( face->os2.version != 0xFFFFU && root->ascender ) { FT_Int height; root->ascender = face->os2.sTypoAscender; root->descender = -face->os2.sTypoDescender; height = root->ascender + root->descender + face->os2.sTypoLineGap; if ( height > root->height ) root->height = height; } #endif /* 0 */ root->max_advance_width = face->horizontal.advance_Width_Max; root->max_advance_height = (FT_Short)( face->vertical_info ? face->vertical.advance_Height_Max : root->height ); root->underline_position = face->postscript.underlinePosition; root->underline_thickness = face->postscript.underlineThickness; /* root->max_points -- already set up */ /* root->max_contours -- already set up */ } } Exit: return error; }