Skip to content

Fonts across platforms

Oleg Oshmyan edited this page Nov 22, 2023 · 18 revisions

This page records observations on the behaviour of various external font APIs.

Names in fonts

Font family names (see below for meanings):

  • Plain “family name” = TrueType/OpenType name ID 1. Paired with “subfamily name”, ID 2.
  • “Typographic family name” = TrueType/OpenType name ID 16. Paired with “typographic subfamily name”, ID 17. If absent, assumed equal to plain (sub)family/ name.
  • “WWS family name” = TrueType/OpenType name ID 21. Paired with “WWS subfamily name”, ID 22. If absent, synthesized from typographic (sub)family name. “WWS” refers to “weight/width/slope”, but when not abbreviating, Microsoft actually uses the terms “weight”, “stretch”, “style” and “weight/stretch/style family” for the same.

Individual font names:

  • “Unique name” = TrueType/OpenType name ID 3. Meant to uniquely identify this particular version of this particular font file, e. g. to facilitate caching of generated glyph bitmaps. Not normally used for font lookup. Usually contains the font’s actual name, version number and possibly date or vendor name. However, Microsoft’s fonts merely contain a verbose font name with vendor name, without any versioning information.
  • “Full name” = TrueType/OpenType name ID 4. This should uniquely identify this particular font face. Usually, this is equal to “Family Subfamily” for each of the three kinds of (sub)family name, but redundant subfamily names can be omitted, some words can be reordered due to the different family name splits, and some names can be abbreviated.
  • “PostScript name” = TrueType/OpenType name ID 6. Known simply as “font name” in PostScript/Type 1 fonts. This should uniquely identify this particular font face and follow PostScript language rules and conventions; in particular, this name should contain no spaces. Usually, this name consists of CamelCase Latin letters and hyphens separating family from subfamily, matching either the English full name or an abbreviation of it. If the font contains PostScript names marked for multiple platforms, encodings or languages, they should all be identical.

Usually, the three kinds of family names differ only in Microsoft-platform names. This document will refer to Microsoft-platform plain family names as GDI family names, because they are the only kind of family names exposed or used by GDI.

By convention, fonts are given GDI family names such that a single “family” contains only up to four fonts, one for each bold/italic combination:

  • Regular
  • Bold
  • Italic
  • Bold Italic

This allows the four fonts to be linked, powering “bold” and “italic” buttons in text editors.

This may or may not have been required on older Microsoft systems and in older third-party software, but both GDI and DirectWrite are actually able to handle many-font families that do not follow this convention, if such font families should exist.

The WWS family name is an extension of this notion to arbitrary weight/stretch/style variations: fonts that share a WWS family name must share a specific visual design and differ only in weight, width/stretch (condensed, expanded etc.) and style (three options: upright, italic or oblique), but with any number of gradations.

The typographic family name denotes the potentially-wider family of fonts with a common overarching design and name but possibly additional stylistic variations.

Non-Microsoft-platform names usually include only the plain family name (ID 1) and set it equal to the Microsoft-platform typographic family name.

Windows

Mostly verified on Windows XP, 7 and 10. Behaviour related to font managers/dynamic fonts is hearsay.

CreateFontIndirect+SelectObject (VSFilter)

  • For TrueType fonts, uses names with the same platform and encoding as the first valid Microsoft-platform cmap (if any) or MacRoman cmap (otherwise). Never uses Unicode-platform names.
  • Finds a TrueType font if either its GDI family name (ID 1) or its full name (ID 4) in a language best matching the current system locale equals the sought name:
    1. Uses the first name with an exact locale match if it exists.
    2. Otherwise, uses the first name with the same major language, except for a Chinese locale, the first name that is either same-Traditional/Simplified Chinese or English.
    3. Otherwise, uses the first English name, except for a Chinese locale, the first name that is another variant of Chinese.
    4. Otherwise, uses the first name.
  • Finds a TrueType font if its first GDI family name (ID 1) in any language (or the second if the first name is the main name per above) equals the sought name.
  • Ignores all other names for TrueType fonts. In particular, does not always find a TrueType font by English name.
  • Finds a CFF-outline OpenType font if any of its Microsoft-platform GDI family names (ID 1) equals the sought name. (More research needed: do cmaps matter?)
  • Finds a CFF-outline OpenType font if its PostScript name equals the sought name.
  • Finds a Type 1 font if its Windows name, as defined in the PFM file, equals the sought name. (More research needed on encoding. It seems to be the user’s current ANSI encoding, and merely setting dfCharSet does not seem to override it.)
  • Finds a Type 1 font if its PostScript name, as defined in the PFM file and in the PFB file’s FontName field (which must match for the font to be installed), equals the sought name.
  • Finds TrueType fonts in TrueType Collection files.
  • Applies name-specific and name-and-charset-specific font substitutions listed in the registry.
  • Untested: since Windows 10 Anniversary Update (version 1607; 10.0; Build 14393), finds CFF-outline OpenType fonts in font collection files.
  • Since Windows 10 Creators Update (version 1703; 10.0; Build 15063), finds a variable font’s predefined variant by name + variant name. (More research needed.)
  • Finds fonts activated on demand by various font managers.

EnumFonts, EnumFontFamilies, EnumFontFamiliesEx with name

  • If some fonts have the sought family name and some other fonts have the sought full-or-PostScript name, returns only the family name matches.
  • Other than that, finds any font that the above (CreateFontIndirect+SelectObject) finds.
  • Exposes for reading only one family name (the best localized one) and one full-or-PostScript name.
  • Returns both real matching fonts and substituted fonts.
  • For substituted fonts, the exposed family name is the fake name (the sought name).
    • Except that on Windows 7 and 10, but not XP, this is true only for the first 32 fonts returned. The rest have their real names. (Bug?)

EnumFonts, EnumFontFamilies with nonnull name

  • EnumFonts only finds at most one font for each bold/italics flag combination (per fsSelection); but this is counted separately for real matching fonts and for substituted fonts, separately for public and private fonts, separately for global and device fonts, and in some cases separately for TrueType and non-TrueType fonts.
  • For fonts listed in some charset-specific font substitutions, returns each substitutable name-and-charset as a separate additional font (even if the sought name itself is a charset-specific substitutable font name).

EnumFontFamiliesEx with nonempty name

  • Returns each charset of each font separately (even if the sought name is a charset-specific substitutable font name).

IDWriteGdiInterop::CreateFontFromLOGFONT, IDWriteGdiInterop1::GetMatchingFontsByLOGFONT

  • Finds a TrueType or CFF-outline OpenType font if any of its Microsoft-platform GDI family names (ID 1) equals the sought name. (More research needed: do encodings and cmaps matter?)
  • In Windows 7, ignores full names. In Windows 10, finds a font if any of its (Microsoft-platform?) full names (ID 4) equals the sought name. (More research needed: do outline formats, platforms, encodings and cmaps matter?)
  • Ignores PostScript names.
  • Does not find Type 1 fonts.
  • Finds fonts activated on demand by font managers, but only if their paths use backslashes.

IDWriteFactory::GetSystemFontCollection

  • Untested: does not expose Type 1 fonts.
  • Untested: since Windows 10 Anniversary Update (version 1607; 10.0; Build 14393), exposes fonts activated on demand by font managers or added via AddFontResource by MKV demuxers.

IDWriteFontFamily

  • By default, groups fonts by their WWS family name, which is synthesized for fonts that lack them, apparently in the same way that Windows Presentation Foundation does it. (Wayback Machine)
  • Since Windows 10 Fall Creators Update (version 1709; 10.0; Build 16299), supports grouping fonts by their typographic family name.

macOS

CTFont

  • Reads Unicode-, Macintosh- and Microsoft-platform names but prefers Macintosh-platform names.
  • Makes no distinction between plain and typographic family names. (Prefers typographic family names for display.) Generally, fonts have the same Macintosh-platform family name (ID 1) as their Microsoft-platform typographic family (ID 16) if it is present.
  • Ignores WWS family names (at least on macOS 10.13).
  • Exposes only a single English and a single localized name (based on the user’s language preferences) of each kind.
  • More research needed: what exactly is the “display name”? Is it related to TrueType name ID 18?
  • More research needed: which family names are read/preferred in fonts with Microsoft-platform names only?

CTFontCollectionCreateMatchingFontDescriptors

  • Matches Microsoft-platform names even if CTFont does not expose them.
  • Matches a name if the font’s English name equals the sought name.
  • For at least some fonts, matches a name if the font’s main-language localized name (regardless of the user’s preferences) equals the sought name. Unclear how it determines the main language.

CTFontCreateForString

  • Alters preferred fallback fonts based on the user’s language preferences.

Fontconfig

  • Reads all platforms’ names and makes no distinction between the platforms.
  • Makes no distinction between the various kinds of family name.