diff --git a/src/fcfreetype.c b/src/fcfreetype.c index baf13e5..49dd427 100644 --- a/src/fcfreetype.c +++ b/src/fcfreetype.c @@ -51,7 +51,9 @@ #include #include #include FT_FREETYPE_H +#include FT_ADVANCES_H #include FT_TRUETYPE_TABLES_H +#include FT_TRUETYPE_TAGS_H #include FT_SFNT_NAMES_H #include FT_TRUETYPE_IDS_H #include FT_TYPE1_TABLES_H @@ -2293,14 +2295,25 @@ FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4) return 0; } +typedef struct _FcFreeTypeCheckGlyphInfo +{ + unsigned int num_glyphs; + FcBool long_offset; + union { + FcChar32 u32[1]; + FcChar16 u16[1]; + } offsets; +} FcFreeTypeCheckGlyphInfo; + static FcBool -FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4, +FcFreeTypeCheckGlyph (FT_Face face, + FcFreeTypeCheckGlyphInfo *info, + FcChar32 ucs4, FT_UInt glyph, FcBlanks *blanks, FT_Pos *advance, FcBool using_strike) { FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; - FT_GlyphSlot slot; if (using_strike) load_flags &= ~FT_LOAD_NO_SCALE; @@ -2315,48 +2328,55 @@ FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4, if (face->face_flags & FT_FACE_FLAG_SCALABLE) load_flags |= FT_LOAD_NO_BITMAP; - if (FT_Load_Glyph (face, glyph, load_flags)) - return FcFalse; + /* + * Previously, we used to load glyphs here... + * If the load succeeded, then for bitmap fonts we were + * accepting, and for outline glyphs, we'd check whether + * the outline is non-empty... + * + * The new logic skips much of that and only checks for + * outline non-emptiness for TrueType outlines. We might + * want to add logic to load glyphs for bitmap-only fonts + * again. If not, there's a whole lot more cruft that can + * be removed... + */ - slot = face->glyph; - if (!glyph) - return FcFalse; + if (advance) + { + *advance = 0; + FT_Get_Advance (face, glyph, load_flags, advance); + } - *advance = slot->metrics.horiAdvance; + if (info) + { + if (glyph >= info->num_glyphs) + return FcFalse; - switch ((int) slot->format) { - case ft_glyph_format_bitmap: - /* - * Bitmaps are assumed to be reasonable; if - * this proves to be a rash assumption, this - * code can be easily modified - */ - return FcTrue; - case ft_glyph_format_outline: - /* - * Glyphs with contours are always OK - */ - if (slot->outline.n_contours != 0) - return FcTrue; - /* - * Glyphs with no contours are only OK if - * they're members of the Blanks set specified - * in the configuration. If blanks isn't set, - * then allow any glyph to be blank - */ - if (!blanks || FcBlanksIsMember (blanks, ucs4)) - return FcTrue; - /* fall through ... */ - default: - break; + if ((info->long_offset ? + info->offsets.u32[glyph] == info->offsets.u32[glyph+1] : + info->offsets.u16[glyph] == info->offsets.u16[glyph+1])) + { + /* + * Glyphs with no contours are only OK if + * they're members of the Blanks set specified + * in the configuration. If blanks isn't set, + * then allow any glyph to be blank + */ + return !blanks || FcBlanksIsMember (blanks, ucs4); + } } - return FcFalse; + + return FcTrue; } #define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33) static FcCharSet * -FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing, FT_Int strike_index) +FcFreeTypeCharSetAndSpacingForSize (FT_Face face, + FcFreeTypeCheckGlyphInfo *info, + FcBlanks *blanks, + int *spacing, + FT_Int strike_index) { FcChar32 page, off, ucs4; #ifdef CHECK @@ -2403,7 +2423,7 @@ FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing ucs4 = map->ent[i].bmp; glyph = FT_Get_Char_Index (face, map->ent[i].encode); if (glyph && - FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike)) + FcFreeTypeCheckGlyph (face, info, ucs4, glyph, blanks, &advance, using_strike)) { /* * ignore glyphs with zero advance. They’re @@ -2451,7 +2471,7 @@ FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing ucs4 = FT_Get_First_Char (face, &glyph); while (glyph != 0) { - if (FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike)) + if (FcFreeTypeCheckGlyph (face, info, ucs4, glyph, blanks, &advance, using_strike)) { if (advance) { @@ -2518,7 +2538,7 @@ FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing { ucs4 = FcGlyphNameToUcs4 (name_buf); if (ucs4 != 0xffff && - FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike)) + FcFreeTypeCheckGlyph (face, info, ucs4, glyph, blanks, &advance, using_strike)) { if (advance) { @@ -2561,7 +2581,7 @@ FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing if (has_char && !has_bit) { - if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike)) + if (!FcFreeTypeCheckGlyph (face, info, ucs4, glyph, blanks, &advance, using_strike)) printf ("Bitmap missing broken char 0x%x\n", ucs4); else printf ("Bitmap missing char 0x%x\n", ucs4); @@ -2587,28 +2607,63 @@ FcCharSet * FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing) { FcCharSet *cs; + FT_Int strike_index = -1; + TT_Header *head_table = FT_Get_Sfnt_Table (face, ft_sfnt_head); + FcFreeTypeCheckGlyphInfo *info = NULL; - /* - * Check for bitmap-only ttf fonts that are missing the glyf table. - * In that case, pick a size and look for glyphs in that size instead - */ - if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && - face->num_fixed_sizes > 0 && - FT_Get_Sfnt_Table (face, ft_sfnt_head)) + if (head_table) { - FT_Int strike_index = 0; - int i; - - /* Select the face closest to 16 pixels tall */ - for (i = 1; i < face->num_fixed_sizes; i++) { - if (abs (face->available_sizes[i].height - 16) < - abs (face->available_sizes[strike_index].height - 16)) - strike_index = i; + /* + * Check for bitmap-only ttf fonts that are missing the glyf table. + * In that case, pick a size and look for glyphs in that size instead + */ + if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && face->num_fixed_sizes > 0) + { + int i; + + strike_index = 0; + + /* Select the face closest to 16 pixels tall */ + for (i = 1; i < face->num_fixed_sizes; i++) { + if (abs (face->available_sizes[i].height - 16) < + abs (face->available_sizes[strike_index].height - 16)) + strike_index = i; + } + } + else if (head_table->Glyph_Data_Format == 0) + { + /* Try loading the 'loca' table, which we will later use to detect + * glyphs without outline (to reject them). If font is other than + * TrueType outlines, we bypass that check. */ + unsigned int num_glyphs = face->num_glyphs; + FcBool long_offset = head_table->Index_To_Loc_Format > 0; + FT_ULong needed_len = (num_glyphs + 1) * (long_offset ? 4 : 2); + FT_ULong table_len = 0; + if (FT_Err_Ok == FT_Load_Sfnt_Table (face, TTAG_loca, 0, NULL, &table_len) && + (table_len = FC_MIN(needed_len, table_len)) >= (long_offset ? 4 : 2) && + (info = malloc (sizeof (*info) + table_len))) + { + if (FT_Err_Ok != FT_Load_Sfnt_Table (face, TTAG_loca, 0, + (FT_Byte *)&info->offsets, &table_len)) + { + free (info); + info = NULL; + } + else + { + info->num_glyphs = FC_MIN(num_glyphs, + (table_len / (long_offset ? 4 : 2)) - 1); + info->long_offset = long_offset; + } + } } - cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, strike_index); } - else - cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, -1); + + cs = FcFreeTypeCharSetAndSpacingForSize (face, info, blanks, spacing, strike_index); + + if (info) + free (info); + return cs; }