Skip to content

Commit

Permalink
fontselect: overhaul font scoring and faux-ing; fixes libass#437
Browse files Browse the repository at this point in the history
This emulates GDI's behavior, both around scoring and faux decisions.

The fontconfig provider doesn't provide the full information we'd need to handle this 100% accurately, so it's best-guessed.
  • Loading branch information
rcombs committed May 13, 2024
1 parent 3f153be commit cd223f9
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 33 deletions.
30 changes: 28 additions & 2 deletions libass/ass_font.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,29 @@ int ass_face_get_weight(FT_Face face)
}
}

static FT_Long fsSelection_to_style_flags(uint16_t fsSelection)
{
FT_Long ret = 0;

if (fsSelection & 1)
ret |= FT_STYLE_FLAG_ITALIC;
if (fsSelection & (1 << 5))
ret |= FT_STYLE_FLAG_BOLD;

return ret;
}

FT_Long ass_face_get_style_flags(FT_Face face)
{
// If we have an OS/2 table, compute this ourselves, since FreeType
// will mix in some flags that GDI ignores.
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
if (os2)
return fsSelection_to_style_flags(os2->fsSelection);

return face->style_flags;
}

/**
* \brief Get maximal font ascender and descender.
**/
Expand Down Expand Up @@ -693,9 +716,12 @@ bool ass_font_get_glyph(ASS_Font *font, int face_index, int index,
index);
return false;
}
if (!(face->style_flags & FT_STYLE_FLAG_ITALIC) && (font->desc.italic > 55))

FT_Long style_flags = ass_face_get_style_flags(face);
if (!(style_flags & FT_STYLE_FLAG_ITALIC) && (font->desc.italic > 55))
ass_glyph_italicize(face->glyph);
if (font->desc.bold > ass_face_get_weight(face) + 150)
if (!(style_flags & FT_STYLE_FLAG_BOLD) &&
font->desc.bold > ass_face_get_weight(face) + 150)
ass_glyph_embolden(face->glyph);
return true;
}
Expand Down
1 change: 1 addition & 0 deletions libass/ass_font.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ void ass_charmap_magic(ASS_Library *library, FT_Face face);
ASS_Font *ass_font_new(ASS_Renderer *render_priv, ASS_FontDesc *desc);
void ass_face_set_size(FT_Face face, double size);
int ass_face_get_weight(FT_Face face);
FT_Long ass_face_get_style_flags(FT_Face face);
void ass_font_get_asc_desc(ASS_Font *font, int face_index,
int *asc, int *desc);
int ass_font_get_index(ASS_FontSelector *fontsel, ASS_Font *font,
Expand Down
6 changes: 5 additions & 1 deletion libass/ass_fontconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ static void scan_fonts(FcConfig *config, ASS_FontProvider *provider)
FcBool outline;
int index;
double weight;
int slant;
char *path;
char *fullnames[MAX_NAME];
char *families[MAX_NAME];
Expand All @@ -108,7 +109,7 @@ static void scan_fonts(FcConfig *config, ASS_FontProvider *provider)
continue;

// simple types
result = FcPatternGetInteger(pat, FC_SLANT, 0, &meta.slant);
result = FcPatternGetInteger(pat, FC_SLANT, 0, &slant);
result |= FcPatternGetDouble(pat, FC_WEIGHT, 0, &weight);
result |= FcPatternGetInteger(pat, FC_INDEX, 0, &index);
if (result != FcResultMatch)
Expand Down Expand Up @@ -158,6 +159,9 @@ static void scan_fonts(FcConfig *config, ASS_FontProvider *provider)
meta.weight = 1000;
#endif

// Take a guess at the italic flag
meta.style_flags = (slant >= FC_SLANT_ITALIC) ? FT_STYLE_FLAG_ITALIC : 0;

// path
result = FcPatternGetString(pat, FC_FILE, 0, (FcChar8 **)&path);
if (result != FcResultMatch)
Expand Down
59 changes: 30 additions & 29 deletions libass/ass_fontselect.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include FT_FREETYPE_H
#include FT_SFNT_NAMES_H
#include FT_TRUETYPE_IDS_H
#include FT_TRUETYPE_TABLES_H
#include FT_TYPE1_TABLES_H

#include "ass_utils.h"
Expand All @@ -60,8 +61,8 @@ struct font_info {
int n_family;
int n_fullname;

int slant;
int weight; // TrueType scale, 100-900
FT_Long style_flags;
int weight; // TrueType scale, 100-900

// how to access this face
char *path; // absolute path
Expand Down Expand Up @@ -256,7 +257,6 @@ get_font_info(FT_Library lib, FT_Face face, const char *fallback_family_name,
int num_fullname = 0;
int num_family = 0;
int num_names = FT_Get_Sfnt_Name_Count(face);
int slant, weight;
char *fullnames[MAX_FULLNAME];
char *families[MAX_FULLNAME];
PS_FontInfoRec postscript_info;
Expand Down Expand Up @@ -309,13 +309,9 @@ get_font_info(FT_Library lib, FT_Face face, const char *fallback_family_name,
if (num_family == 0)
goto error;

// calculate sensible slant and weight from style attributes
slant = 110 * !!(face->style_flags & FT_STYLE_FLAG_ITALIC);
weight = ass_face_get_weight(face);

// fill our struct
info->slant = slant;
info->weight = weight;
// calculate sensible weight
info->weight = ass_face_get_weight(face);
info->style_flags = ass_face_get_style_flags(face);

info->postscript_name = (char *)FT_Get_Postscript_Name(face);
info->is_postscript = !FT_Get_PS_Font_Info(face, &postscript_info);
Expand Down Expand Up @@ -389,7 +385,6 @@ ass_font_provider_add_font(ASS_FontProvider *provider,
int index, void *data)
{
int i;
int weight, slant;
ASS_FontSelector *selector = provider->parent;
ASS_FontInfo *info = NULL;
ASS_FontProviderMetaData implicit_meta = {0};
Expand Down Expand Up @@ -445,21 +440,12 @@ ass_font_provider_add_font(ASS_FontProvider *provider,
for (j = 0; j < meta->n_fullname; j++)
printf("'%s' ", meta->fullnames[j]);
printf("\n");
printf(" slant: %d\n", meta->slant);
printf(" style_flags: %lx\n", meta->style_flags);
printf(" weight: %d\n", meta->weight);
printf(" path: %s\n", path);
printf(" index: %d\n", index);
#endif

weight = meta->weight;
slant = meta->slant;

// check slant/weight for validity, use defaults if they're invalid
if (weight < 100 || weight > 900)
weight = 400;
if (slant < 0 || slant > 110)
slant = 0;

// check size
if (selector->n_font >= selector->alloc_font) {
selector->alloc_font = FFMAX(1, 2 * selector->alloc_font);
Expand All @@ -474,8 +460,8 @@ ass_font_provider_add_font(ASS_FontProvider *provider,
// set uid
info->uid = selector->uid++;

info->slant = slant;
info->weight = weight;
info->style_flags = meta->style_flags;
info->weight = meta->weight;
info->n_fullname = meta->n_fullname;
info->n_family = meta->n_family;
info->is_postscript = meta->is_postscript;
Expand Down Expand Up @@ -668,11 +654,26 @@ static bool matches_full_or_postscript_name(ASS_FontInfo *f,
*/
static unsigned font_attributes_similarity(ASS_FontInfo *a, ASS_FontInfo *req)
{
unsigned similarity = 0;
similarity += ABS(a->weight - req->weight);
similarity += ABS(a->slant - req->slant);
unsigned score = 0;

// Assign score for italics mismatch
if ((req->style_flags & FT_STYLE_FLAG_ITALIC) &&
!(a->style_flags & FT_STYLE_FLAG_ITALIC))
score += 1;
else if (!(req->style_flags & FT_STYLE_FLAG_ITALIC) &&
(a->style_flags & FT_STYLE_FLAG_ITALIC))
score += 4;

int a_weight = a->weight;

// Offset effective weight for faux-bold (only if font isn't flagged as bold)
if ((req->weight > a->weight + 150) && !(a->style_flags & FT_STYLE_FLAG_BOLD))
a_weight += 120;

// Assign score for weight mismatch
score += (73 * ABS(a_weight - req->weight)) / 256;

return similarity;
return score;
}

#if 0
Expand Down Expand Up @@ -724,8 +725,8 @@ find_font(ASS_FontSelector *priv,
return NULL;

// fill font request
req.slant = italic;
req.weight = bold;
req.style_flags = (italic ? FT_STYLE_FLAG_ITALIC : 0);
req.weight = bold;

// Match font family name against font list
unsigned score_min = UINT_MAX;
Expand Down
2 changes: 1 addition & 1 deletion libass/ass_fontselect.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ struct ass_font_provider_meta_data {
int n_family; // Number of localized family names
int n_fullname; // Number of localized full names

int slant; // Font slant value from FONT_SLANT_*
FT_Long style_flags; // Computed from OS/2 table, or equivalent
int weight; // Font weight in TrueType scale, 100-900
// See FONT_WEIGHT_*

Expand Down

0 comments on commit cd223f9

Please sign in to comment.