Instead of loading glyphs (with FreeType), just check loca table
Part of https://bugs.freedesktop.org/show_bug.cgi?id=64766#c47 This is the approach introduced in https://bugs.freedesktop.org/show_bug.cgi?id=64766#c30 Testing it with 11GB worth of stuff, before/after: behdad:src 130$ time fc-scan ~/fonts/ > before real 2m18.428s user 1m17.008s sys 0m20.576s behdad:src 0$ time fc-scan ~/fonts/ > after real 1m12.130s user 0m18.180s sys 0m19.952s Running the after case a second time is significantly faster: behdad:src 130$ time fc-scan ~/fonts/ > after real 0m24.825s user 0m12.408s sys 0m11.356s Next I'm going to try to not even read loca...
This commit is contained in:
parent
339de167c7
commit
ab02a49490
169
src/fcfreetype.c
169
src/fcfreetype.c
|
@ -51,7 +51,9 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ft2build.h>
|
#include <ft2build.h>
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
|
#include FT_ADVANCES_H
|
||||||
#include FT_TRUETYPE_TABLES_H
|
#include FT_TRUETYPE_TABLES_H
|
||||||
|
#include FT_TRUETYPE_TAGS_H
|
||||||
#include FT_SFNT_NAMES_H
|
#include FT_SFNT_NAMES_H
|
||||||
#include FT_TRUETYPE_IDS_H
|
#include FT_TRUETYPE_IDS_H
|
||||||
#include FT_TYPE1_TABLES_H
|
#include FT_TYPE1_TABLES_H
|
||||||
|
@ -2197,14 +2199,25 @@ FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct _FcFreeTypeCheckGlyphInfo
|
||||||
|
{
|
||||||
|
unsigned int num_glyphs;
|
||||||
|
FcBool long_offset;
|
||||||
|
union {
|
||||||
|
FcChar32 u32[1];
|
||||||
|
FcChar16 u16[1];
|
||||||
|
} offsets;
|
||||||
|
} FcFreeTypeCheckGlyphInfo;
|
||||||
|
|
||||||
static FcBool
|
static FcBool
|
||||||
FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
|
FcFreeTypeCheckGlyph (FT_Face face,
|
||||||
|
FcFreeTypeCheckGlyphInfo *info,
|
||||||
|
FcChar32 ucs4,
|
||||||
FT_UInt glyph, FcBlanks *blanks,
|
FT_UInt glyph, FcBlanks *blanks,
|
||||||
FT_Pos *advance,
|
FT_Pos *advance,
|
||||||
FcBool using_strike)
|
FcBool using_strike)
|
||||||
{
|
{
|
||||||
FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
|
FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
|
||||||
FT_GlyphSlot slot;
|
|
||||||
|
|
||||||
if (using_strike)
|
if (using_strike)
|
||||||
load_flags &= ~FT_LOAD_NO_SCALE;
|
load_flags &= ~FT_LOAD_NO_SCALE;
|
||||||
|
@ -2219,48 +2232,55 @@ FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
|
||||||
if (face->face_flags & FT_FACE_FLAG_SCALABLE)
|
if (face->face_flags & FT_FACE_FLAG_SCALABLE)
|
||||||
load_flags |= FT_LOAD_NO_BITMAP;
|
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 (advance)
|
||||||
if (!glyph)
|
{
|
||||||
return FcFalse;
|
*advance = 0;
|
||||||
|
FT_Get_Advance (face, glyph, load_flags, advance);
|
||||||
*advance = slot->metrics.horiAdvance;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
return FcFalse;
|
|
||||||
|
if (info)
|
||||||
|
{
|
||||||
|
if (glyph >= info->num_glyphs)
|
||||||
|
return FcFalse;
|
||||||
|
|
||||||
|
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 FcTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
|
#define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
|
||||||
|
|
||||||
static FcCharSet *
|
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;
|
FcChar32 page, off, ucs4;
|
||||||
#ifdef CHECK
|
#ifdef CHECK
|
||||||
|
@ -2300,7 +2320,7 @@ FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing
|
||||||
ucs4 = FT_Get_First_Char (face, &glyph);
|
ucs4 = FT_Get_First_Char (face, &glyph);
|
||||||
while (glyph != 0)
|
while (glyph != 0)
|
||||||
{
|
{
|
||||||
if (FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
|
if (FcFreeTypeCheckGlyph (face, info, ucs4, glyph, blanks, &advance, using_strike))
|
||||||
{
|
{
|
||||||
if (advance)
|
if (advance)
|
||||||
{
|
{
|
||||||
|
@ -2386,7 +2406,7 @@ FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing
|
||||||
{
|
{
|
||||||
ucs4 = FcGlyphNameToUcs4 (name_buf);
|
ucs4 = FcGlyphNameToUcs4 (name_buf);
|
||||||
if (ucs4 != 0xffff &&
|
if (ucs4 != 0xffff &&
|
||||||
FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
|
FcFreeTypeCheckGlyph (face, info, ucs4, glyph, blanks, &advance, using_strike))
|
||||||
{
|
{
|
||||||
if (advance)
|
if (advance)
|
||||||
{
|
{
|
||||||
|
@ -2429,7 +2449,7 @@ FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing
|
||||||
|
|
||||||
if (has_char && !has_bit)
|
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);
|
printf ("Bitmap missing broken char 0x%x\n", ucs4);
|
||||||
else
|
else
|
||||||
printf ("Bitmap missing char 0x%x\n", ucs4);
|
printf ("Bitmap missing char 0x%x\n", ucs4);
|
||||||
|
@ -2455,28 +2475,63 @@ FcCharSet *
|
||||||
FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
|
FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
|
||||||
{
|
{
|
||||||
FcCharSet *cs;
|
FcCharSet *cs;
|
||||||
|
FT_Int strike_index = -1;
|
||||||
|
TT_Header *head_table = FT_Get_Sfnt_Table (face, ft_sfnt_head);
|
||||||
|
FcFreeTypeCheckGlyphInfo *info = NULL;
|
||||||
|
|
||||||
/*
|
if (head_table)
|
||||||
* 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))
|
|
||||||
{
|
{
|
||||||
FT_Int strike_index = 0;
|
/*
|
||||||
int 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;
|
||||||
|
|
||||||
/* Select the face closest to 16 pixels tall */
|
strike_index = 0;
|
||||||
for (i = 1; i < face->num_fixed_sizes; i++) {
|
|
||||||
if (abs (face->available_sizes[i].height - 16) <
|
/* Select the face closest to 16 pixels tall */
|
||||||
abs (face->available_sizes[strike_index].height - 16))
|
for (i = 1; i < face->num_fixed_sizes; i++) {
|
||||||
strike_index = 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;
|
return cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue