Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better support for variable fonts #151

Open
dominikh opened this issue Mar 27, 2024 · 3 comments
Open

Better support for variable fonts #151

dominikh opened this issue Mar 27, 2024 · 3 comments

Comments

@dominikh
Copy link
Contributor

dominikh commented Mar 27, 2024

I've noticed the following shortcomings in the handling of variable fonts / font variations:

  • Given an opentype/api/font.Font or Face, it's not possible to determine what axes the font offers. Face has a Coords field that's documented as "It is empty for non variable fonts.", but since we create faces by simply wrapping fonts in them, Coords is also empty if Face.SetVariations hasn't been called, in which case the font is using its default values. I haven't found any other way to know which axes a font supports. I believe what we want is to expose the fvar and STAT tables of a font.
  • fontscan is fully unaware of variable fonts. It doesn't use axes to fulfill requests, and footprint doesn't record which axes a font offers, either.
@dominikh
Copy link
Contributor Author

Overall, this package seems somewhat designed around the WWS font model. For example, opentype/api/metadata.Describe prefers returning a family name that fits into the WWS model, which won't be a great fit for variable fonts.

@benoitkugler
Copy link
Contributor

opentype/api/metadata.Describe prefers returning a family name that fits into the WWS model,

I'm not sure I'm following you here. Could you explain why would be the alternatives ?

@dominikh
Copy link
Contributor Author

(This is somewhat orthogonal to variable fonts.)

This is the method in question:

// Family returns the font family name.
func (fd *fontDescriptor) Family() string {
	var family string
	if fd.os2 != nil && fd.os2.FsSelection&256 != 0 {
		family = fd.names.Name(namePreferredFamily)
		if family == "" {
			family = fd.names.Name(nameFontFamily)
		}
	} else {
		family = fd.names.Name(nameWWSFamily)
		if family == "" {
			family = fd.names.Name(namePreferredFamily)
		}
		if family == "" {
			family = fd.names.Name(nameFontFamily)
		}
	}
	return family
}

if I'm following the code correctly, this only uses the preferred family (aka the typographic family) if it fits the WWS model, and else it uses the WWS family (ignoring the fallbacks when either is empty).

Say we have a typographic family "Minion Pro" that has optical sizes "Caption" and "Display". Because optical sizes aren't part of the WWS model, this will have the WWS family names "Minion Pro Caption" and "Minion Pro Display". The typographic name, however, would be "Minion Pro", and group the two fonts under the same family.

https://learn.microsoft.com/en-us/typography/opentype/spec/name goes into more details on this. If you grep for The following is an example of family/subfamily naming for an extended, non-WWS family you will find the Minion Pro example.

In the end, it's a matter of what font model the application wants to expose to the user: R/B/I/BI, WWS, or the "extended" one which allows arbitrary axes (which is particularly useful with, but not restricted to, variable fonts.) Different kinds of applications will want access to the different sets of names, although modern, newly written software should arguably support the extended model.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants