go-text / typesetting

High quality text shaping in pure Go.
Other
103 stars 11 forks source link

Better support for variable fonts #151

Open dominikh opened 8 months ago

dominikh commented 8 months ago

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

dominikh commented 8 months ago

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 commented 8 months ago

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 commented 8 months ago

(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.