Skip to content

Commit

Permalink
directwrite: always read metadata on our own via FreeType
Browse files Browse the repository at this point in the history
DirectWrite sometimes returns names that differ from GDI's. Instead of
trusting it, use our own GDI-compatible code, even if it costs us some
extra resources.

Conceptually, this reverts commit 4fb7394
"directwrite: read metadata from IDWriteFontFace3 if possible":
the refactoring is kept, and so is the read of the PostScript name
purely for logging purposes in case of error, but we turn back to
(re)reading all metadata on our own. In addition to reverting the logic
of the IDWriteFontFace3 path, this also makes the CreateFontFromLOGFONT
path similarly go via FreeType.

This fixes libass#675
and facilitates future improvements to long font name matching
(libass#459).

To avoid exotic failures, especially font fallback failures,
save DirectWrite's WIN32_FAMILY_NAME as our extended_family.
get_fallback returns the WIN32_FAMILY_NAME, and it *should* match what
we read for the same font via FreeType, but it is not unfathomable that
in some exotic cases it might not match or we might not read any family
names at all. fontselect consults the extended_family for fallback fonts
and for primary fonts that otherwise have no family names.

We might actually want to use WWS_FAMILY_NAME (or presumably equivalently,
DirectWrite's first-class font family names) as the extended_family to
allow better fallback to multi-weight families given tags like \b900,
but there are at least two reasons why WIN32_FAMILY_NAME seems better
at the moment:

  * Across all Windows versions and variants, match_fonts is only
    guaranteed (if even that) to find a font by its WIN32_FAMILY_NAME.
    For the fallback font to work, we obviously need match_fonts
    to be able to find it.

    We could alleviate this by querying DirectWrite for fonts by its
    first-class family name in addition to the primary GDI-based path.

  * While WWS_FAMILY_NAME joins, for example, Arial and Arial Bold,
    which is desirable, it also joins Arial and Arial Narrow, but we
    do not distinguish between fonts that differ only in width/stretch.
    Barring additional width-based ordering logic somewhere, this could
    lead us to choose an inconsistent combination of fallback font faces,
    e. g. regular Arial for \i0 with Arial Narrow Italic for \i1.
  • Loading branch information
astiob committed Jan 21, 2024
1 parent 9f21dbe commit b6650bd
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 61 deletions.
17 changes: 0 additions & 17 deletions libass/ass_directwrite.c
Original file line number Diff line number Diff line change
Expand Up @@ -580,23 +580,6 @@ static char *get_fallback(void *priv, ASS_Library *lib,
return family;
}

static int map_width(enum DWRITE_FONT_STRETCH stretch)
{
switch (stretch) {
case DWRITE_FONT_STRETCH_ULTRA_CONDENSED: return 50;
case DWRITE_FONT_STRETCH_EXTRA_CONDENSED: return 63;
case DWRITE_FONT_STRETCH_CONDENSED: return FONT_WIDTH_CONDENSED;
case DWRITE_FONT_STRETCH_SEMI_CONDENSED: return 88;
case DWRITE_FONT_STRETCH_MEDIUM: return FONT_WIDTH_NORMAL;
case DWRITE_FONT_STRETCH_SEMI_EXPANDED: return 113;
case DWRITE_FONT_STRETCH_EXPANDED: return FONT_WIDTH_EXPANDED;
case DWRITE_FONT_STRETCH_EXTRA_EXPANDED: return 150;
case DWRITE_FONT_STRETCH_ULTRA_EXPANDED: return 200;
default:
return FONT_WIDTH_NORMAL;
}
}

#define FONT_TYPE IDWriteFontFace3
#include "ass_directwrite_info_template.h"
#undef FONT_TYPE
Expand Down
49 changes: 5 additions & 44 deletions libass/ass_directwrite_info_template.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,8 @@ static bool NAME(FONT_TYPE)(FONT_TYPE *font,
HRESULT hr;
BOOL exists;

meta->weight = font->lpVtbl->GetWeight(font);
meta->width = map_width(font->lpVtbl->GetStretch(font));

DWRITE_FONT_STYLE style = font->lpVtbl->GetStyle(font);
meta->slant = (style == DWRITE_FONT_STYLE_NORMAL) ? FONT_SLANT_NONE :
(style == DWRITE_FONT_STYLE_OBLIQUE)? FONT_SLANT_OBLIQUE :
(style == DWRITE_FONT_STYLE_ITALIC) ? FONT_SLANT_ITALIC : FONT_SLANT_NONE;

// This PostScript name will merely be logged by
// ass_face_stream in case it encounters an error
IDWriteLocalizedStrings *psNames;
hr = font->lpVtbl->GetInformationalStrings(font,
DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &psNames, &exists);
Expand All @@ -32,29 +26,6 @@ static bool NAME(FONT_TYPE)(FONT_TYPE *font,
return false;
}

IDWriteLocalizedStrings *fontNames;
hr = font->lpVtbl->GetInformationalStrings(font,
DWRITE_INFORMATIONAL_STRING_FULL_NAME, &fontNames, &exists);
if (FAILED(hr))
return false;

if (exists) {
meta->n_fullname = IDWriteLocalizedStrings_GetCount(fontNames);
meta->fullnames = calloc(meta->n_fullname, sizeof(char *));
if (!meta->fullnames) {
IDWriteLocalizedStrings_Release(fontNames);
return false;
}
for (int k = 0; k < meta->n_fullname; k++) {
meta->fullnames[k] = get_utf8_name(fontNames, k);
if (!meta->fullnames[k]) {
IDWriteLocalizedStrings_Release(fontNames);
return false;
}
}
IDWriteLocalizedStrings_Release(fontNames);
}

IDWriteLocalizedStrings *familyNames;
hr = font->lpVtbl->GetInformationalStrings(font,
DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &familyNames, &exists);
Expand All @@ -68,20 +39,10 @@ static bool NAME(FONT_TYPE)(FONT_TYPE *font,
if (FAILED(hr))
return false;

meta->n_family = IDWriteLocalizedStrings_GetCount(familyNames);
meta->families = calloc(meta->n_family, sizeof(char *));
if (!meta->families) {
IDWriteLocalizedStrings_Release(familyNames);
return false;
}
for (int k = 0; k < meta->n_family; k++) {
meta->families[k] = get_utf8_name(familyNames, k);
if (!meta->families[k]) {
IDWriteLocalizedStrings_Release(familyNames);
return false;
}
}
meta->extended_family = get_utf8_name(familyNames, 0);
IDWriteLocalizedStrings_Release(familyNames);
if (!meta->extended_family)
return false;

return true;
}

0 comments on commit b6650bd

Please sign in to comment.