Separate charset and spacing code

For variable-font named-instances we want to reuse the same charset and redo the spacing.
This commit is contained in:
Behdad Esfahbod 2017-09-27 12:31:03 -04:00
parent 15b5016ccd
commit bf4d440e7f
1 changed files with 64 additions and 44 deletions

View File

@ -2263,18 +2263,13 @@ static inline int fc_max (int a, int b) { return a >= b ? a : b; }
static inline FcBool fc_approximately_equal (int x, int y) static inline FcBool fc_approximately_equal (int x, int y)
{ return abs (x - y) * 33 <= fc_max (abs (x), abs (y)); } { return abs (x - y) * 33 <= fc_max (abs (x), abs (y)); }
FcCharSet * static int
FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks FC_UNUSED, int *spacing) FcFreeTypeSpacing (FT_Face face)
{ {
FcCharSet *fcs;
int o;
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_Pos advances[3] = {}; FT_Pos advances[3] = {};
unsigned int num_advances = spacing ? 0 : 3; unsigned int num_advances = 0;
int o;
fcs = FcCharSetCreate ();
if (!fcs)
goto bail0;
/* When using scalable fonts, only report those glyphs /* When using scalable fonts, only report those glyphs
* which can be scaled; otherwise those fonts will * which can be scaled; otherwise those fonts will
@ -2299,18 +2294,65 @@ FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks FC_UNUSED, int *spac
strike_index = i; strike_index = i;
} }
if (FT_Select_Size (face, strike_index) != FT_Err_Ok) FT_Select_Size (face, strike_index);
goto bail1;
} }
#endif #endif
for (o = 0; o < NUM_DECODE; o++)
{
FcChar32 ucs4;
FT_UInt glyph;
if (FT_Select_Charmap (face, fcFontEncodings[o]) != 0)
continue;
ucs4 = FT_Get_First_Char (face, &glyph);
while (glyph != 0 && num_advances < 3)
{
FT_Pos advance = 0;
if (!FT_Get_Advance (face, glyph, load_flags, &advance) && advance)
{
unsigned int j;
for (j = 0; j < num_advances; j++)
if (fc_approximately_equal (advance, advances[j]))
break;
if (j == num_advances)
advances[num_advances++] = advance;
}
ucs4 = FT_Get_Next_Char (face, ucs4, &glyph);
}
break;
}
if (num_advances <= 1)
return FC_MONO;
else if (num_advances == 2 &&
fc_approximately_equal (fc_min (advances[0], advances[1]) * 2,
fc_max (advances[0], advances[1])))
return FC_DUAL;
else
return FC_PROPORTIONAL;
}
FcCharSet *
FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks FC_UNUSED)
{
const FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
FcCharSet *fcs;
int o;
fcs = FcCharSetCreate ();
if (!fcs)
goto bail;
#ifdef CHECK #ifdef CHECK
printf ("Family %s style %s\n", face->family_name, face->style_name); printf ("Family %s style %s\n", face->family_name, face->style_name);
#endif #endif
for (o = 0; o < NUM_DECODE; o++) for (o = 0; o < NUM_DECODE; o++)
{ {
FcChar32 page, off, ucs4; FcChar32 page, off, ucs4;
FcCharLeaf *leaf; FcCharLeaf *leaf;
FT_UInt glyph; FT_UInt glyph;
if (FT_Select_Charmap (face, fcFontEncodings[o]) != 0) if (FT_Select_Charmap (face, fcFontEncodings[o]) != 0)
@ -2335,26 +2377,13 @@ FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks FC_UNUSED, int *spac
if (good) if (good)
{ {
if (num_advances < 3) FcCharSetAddChar (fcs, ucs4);
{
FT_Pos advance = 0;
if (!FT_Get_Advance (face, glyph, load_flags, &advance) && advance)
{
unsigned int i;
for (i = 0; i < num_advances; i++)
if (fc_approximately_equal (advance, advances[i]))
break;
if (i == num_advances)
advances[num_advances++] = advance;
}
}
if ((ucs4 >> 8) != page) if ((ucs4 >> 8) != page)
{ {
page = (ucs4 >> 8); page = (ucs4 >> 8);
leaf = FcCharSetFindLeafCreate (fcs, ucs4); leaf = FcCharSetFindLeafCreate (fcs, ucs4);
if (!leaf) if (!leaf)
goto bail1; goto bail;
} }
off = ucs4 & 0xff; off = ucs4 & 0xff;
leaf->map[off >> 5] |= (1 << (off & 0x1f)); leaf->map[off >> 5] |= (1 << (off & 0x1f));
@ -2395,29 +2424,20 @@ FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks FC_UNUSED, int *spac
break; break;
} }
if (spacing)
{
if (num_advances <= 1)
*spacing = FC_MONO;
else if (num_advances == 2 &&
fc_approximately_equal (fc_min (advances[0], advances[1]) * 2,
fc_max (advances[0], advances[1])))
*spacing = FC_DUAL;
else
*spacing = FC_PROPORTIONAL;
}
return fcs; return fcs;
bail1: bail:
FcCharSetDestroy (fcs); FcCharSetDestroy (fcs);
bail0:
return 0; return 0;
} }
FcCharSet * FcCharSet *
FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks FC_UNUSED) FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks FC_UNUSED, int *spacing)
{ {
return FcFreeTypeCharSetAndSpacing (face, blanks, NULL);
if (spacing)
*spacing = FcFreeTypeSpacing (face);
return FcFreeTypeCharSet (face, blanks);
} }