[varfonts] Don't reopen face for each named instance

Makes scanning of Voto (over 500 named instaces) twice faster.

Next, avoid charset / lang recalculation for each of those.
This commit is contained in:
Behdad Esfahbod 2017-09-20 19:39:59 -07:00
parent 2d0063948a
commit 15b5016ccd
1 changed files with 74 additions and 62 deletions

View File

@ -2082,8 +2082,9 @@ FcFreeTypeQueryAll(const FcChar8 *file,
int *count, int *count,
FcFontSet *set) FcFontSet *set)
{ {
FT_Face face; FT_Face face = NULL;
FT_Library ftLibrary = NULL; FT_Library ftLibrary = NULL;
FT_MM_Var *mm_var = NULL;
FcBool index_set = id != (unsigned int) -1; FcBool index_set = id != (unsigned int) -1;
unsigned int set_face_num = index_set ? id & 0xFFFF : 0; unsigned int set_face_num = index_set ? id & 0xFFFF : 0;
unsigned int set_instance_num = index_set ? id >> 16 : 0; unsigned int set_instance_num = index_set ? id >> 16 : 0;
@ -2094,75 +2095,86 @@ FcFreeTypeQueryAll(const FcChar8 *file,
unsigned int ret = 0; unsigned int ret = 0;
int err = 0; int err = 0;
if (count)
*count = 0;
if (FT_Init_FreeType (&ftLibrary)) if (FT_Init_FreeType (&ftLibrary))
return 0; return 0;
do { if (FT_New_Face (ftLibrary, (const char *) file, face_num, &face))
FcPattern *pat; goto bail;
id = ((instance_num << 16) + face_num);
if (FT_New_Face (ftLibrary, (const char *) file, id & 0x7FFFFFFF, &face))
break;
num_faces = face->num_faces; num_faces = face->num_faces;
num_instances = face->style_flags >> 16; num_instances = face->style_flags >> 16;
pat = FcFreeTypeQueryFace (face, (const FcChar8 *) file, id, blanks); if (num_instances && (!index_set || instance_num))
if (pat)
{ {
/* Skip named-instance that coincides with base instance. */ FT_Get_MM_Var (face, &mm_var);
if (!index_set && instance_num && instance_num != 0x8000) assert (mm_var);
{
unsigned int i;
FT_MM_Var *mm_var = NULL;
FT_Fixed *coords = NULL;
if (FT_Get_MM_Var (face, &mm_var) ||
!(coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed))) ||
FT_Get_Var_Blend_Coordinates (face, mm_var->num_axis, coords))
{
goto skip;
} }
for (i = 0; i < mm_var->num_axis; i++)
if (coords[i])
goto good;
skip:
free (coords);
FcPatternDestroy (pat);
pat = NULL;
good:
;
}
if (pat)
{
ret++;
if (!set || ! FcFontSetAdd (set, pat))
FcPatternDestroy (pat);
}
}
else if (instance_num != 0x8000)
err = 1;
FT_Done_Face (face);
face = NULL;
if (!set_instance_num && instance_num < num_instances)
instance_num++;
else if (!set_instance_num && instance_num == num_instances)
instance_num = 0x8000; /* variable font */
else
{
face_num++;
instance_num = set_instance_num;
}
} while (!err && (!index_set || face_num == set_face_num) && face_num < num_faces);
if (count) if (count)
*count = num_faces; *count = num_faces;
do {
FcPattern *pat = NULL;
if (instance_num == 0x8000 || instance_num > num_instances)
FT_Set_Var_Design_Coordinates (face, 0, NULL); /* Reset variations. */
else if (instance_num)
{
FT_Var_Named_Style *instance = &mm_var->namedstyle[instance_num - 1];
FT_Fixed *coords = instance->coords;
FcBool nonzero;
unsigned int i;
/* Skip named-instance that coincides with base instance. */
nonzero = FcFalse;
for (i = 0; i < mm_var->num_axis; i++)
if (coords[i] != mm_var->axis[i].def)
{
nonzero = FcTrue;
break;
}
if (!nonzero)
goto skip;
FT_Set_Var_Design_Coordinates (face, mm_var->num_axis, coords);
}
id = ((instance_num << 16) + face_num);
pat = FcFreeTypeQueryFace (face, (const FcChar8 *) file, id, blanks);
if (pat)
{
ret++;
if (!set || ! FcFontSetAdd (set, pat))
FcPatternDestroy (pat);
}
else if (instance_num != 0x8000)
err = 1;
skip:
if (!index_set && instance_num < num_instances)
instance_num++;
else if (!index_set && instance_num == num_instances)
instance_num = 0x8000; /* variable font */
else
{
FT_Done_Face (face);
face = NULL;
face_num++;
instance_num = set_instance_num;
if (FT_New_Face (ftLibrary, (const char *) file, face_num, &face))
break;
}
} while (!err && (!index_set || face_num == set_face_num) && face_num < num_faces);
bail:
if (face)
FT_Done_Face (face);
FT_Done_FreeType (ftLibrary); FT_Done_FreeType (ftLibrary);
return ret; return ret;