Opentype features from variable axes?

Richard Rutter
Richard Rutter Posts: 9
edited November 2017 in Font Technology
Further to Lorp's tweet in which he says "@adamtwarexplains why OpenType features cannot trigger axis position changes" I have a question, which I think is answered therein, but I'd like clarification.

Take the example of small caps. We all know that small caps glyphs can be accessed in a font as an OpenType feature, by way of the `smcp` table. I've also seen an example of small caps built using an axis (Noboto Flex). Could the small caps be 'built' using an axis and accessed as an OpenType feature?

As a web designer, I ask because it feels to me that there would be a file size saving, especially if the technique is extended to other alternates such as numerals. But also OpenType features is the right way to access these glyphs, particularly on the web where you might need to fall back to system fonts if a webfont doesn't load for example.

Comments

  • It's currently not possible. Also: selecting a different instance constitutes a font change, so kerning between variable small caps and the unmodified glyphs wouldn't work. The variable font model could be extended to allow feature interaction between different v instances, but it would be quite complicated. 
  • Belleve Invis
    Belleve Invis Posts: 269
    edited October 2017
    I was always wondering that, the quantification of the variation vector does not happen on the font level, but at the glyph level, so that a glyph is now a function which takes a variation vector, and produces some outlines. You can "call" any glyph with any VV, and the default "parameters" are in the CMAP level.

    More precisely, the current OTVar spec as a type definition in Idris:
    -- Variation vector type with n axes
    -- It is a dependent type
    VV : Nat -> Type
    VV n = Vect n Real
    
    -- A static font
    record StaticFont where
        glyf : GID -> Outline
        cmap : Unicode -> GID
        GSUB : List (GID -> GID)
    
    Font : Nat -> Type
    Font n = VV n -> StaticFont
    If we can have more flexibility:
    -- Font type with n axes
    record Font (n : Nat) where
        glyf : GID -> VV n -> Outline
        cmap : VV n × Unicode -> GID × VV n -- cmap maps a (VV, Unicode) combination to a (GID, VV) combination
        GSUB : List (GID × VV n -> GID × VV n)<br>

  • My test font:

    https://github.com/twardoch/varfonts-ofl/tree/master/ZinzinVF-OFL

    shows how a font axis can be used to gradually trigger different lookups depending on the axis value. 

    Here, it’s done in the "rvrn" feature, but it’s possible to do with any feature. This means: depending on the user-selected axis location, it’s possible to have different GSUB and GPOS realizations for any given feature. 

    For example, you might have a "LIGA" axis that controls in detail how many ligatures are enabled when the "liga" feature is active. The axis may also perform some contour modification, but that’s not required.

    But there is a big caveat: in the current VF model, each selected variable instance constitutes a new font. This means, the glyph run breaks and no features can interact across the change of the instance. The fvar axes are above features, not on the same level.

    It's not difficult to imagine typesetting a series of glyphs and applying a different axis location to each one. But variations don't apply just to glyphs but also to positioning, and different lookups can be triggered depending on the axis location. 

    If different axis locations can trigger different GSUB and GPOS lookups, and any of the lookups could change the axis locations, then quite possibly, the new axis locations would deactivate the lookups that triggered them. 

    Or what if a lookup is executed when an axis it at position 300 and the rule says "move the axis location to 200", but then the same lookup at axis location 200 would have a rule "move the axis location to 100"?

    Also, OpenType GPOS works so that it can change the x/y position of the glyph origin and the x/y position of the glyph advance width point.

    Asking for GSUB to allow mixing instances would mean e.g. if we’re at axis location 300 and if glyph "a" is followed by "b", then move the axis location of glyph "b" to 200. 

    But let’s say we have a string "abc" and there is GPOS adjustment between "b" and "c" that at axis location 300 changes the origin point and the advance width of "b" somehow, and also changes the origin point and the advance width of "c" somehow — to allow kerning, but also more complex positioning.

    Now, when, after GSUB, "b" is at axis location 200 and "c" is at axis location 300, then neiter the GPOS rules for 300 nor those for 200 apply completely. Some things would need to be interpolated — but what? The origin of "b"? The advance width of "b"? The origin of "c"? The advance width of "c"? Both x and y, or only one?

    One more example: if after some GSUB processing we end up with "abc" where "a" and "c" are at axis location 300 but "b" is at axis location 200, and we have some more lookups to process — and those lookups define different behaviors when axis locations are <250 and different if >250, and there are contextual substitutions (let's say "c" is substituted by "d" if preceded by "a" and "b" but only if axis location is >250) — what exactly should happen? Is "b" in-context or out-of-context?

    Oh, or maybe we then should define additional contextual GSUB lookup types which allow for matching contexts not just for which glyphs they are, but also for what axis locations (and then, logically, what x and y distances) they have.

    That would in principally be wonderful — if we could define not just glyph ID-based contexts but also axis location-based and x/y-position-based contexts. But it would be hard. :)

    There are many caveats associated with bidirectional axis-feature interaction. So for now, the interaction is only one way: features can detect at which axis location the font is and apply different lookups depending on that. But it doesn’t go back.

    There’s been some conversation about possibly adding a mechanism that would allow more axis-feature interaction, see:

    http://typedrawers.com/discussion/2109/otvar-changing-tracking-hvar

    But it’s nowhere near drafted. I think for the time being, OpenType Font Variations will remain “font-level variations”. Introducing inter-glyph-level variations is conceptually much more complicated.

    I think many people would agree that in general, something like this is a good idea. But figuring out how to make this work reasonably, writing the spec and implementing it will take time. Positioning is particularly tricky because there is no obvious way to tell what "working reasonably" would mean here. 

    Variable fonts may have intermediate masters where positioning is very "odd". 

    Let's say some glyphs are narrow and tight in the axis location 0, then they become wide and loose in axis location 500 and then they  become narrow and tight (but in a completely different way) in axis location 1000.

    If I put one glyph at location 0 next to another glyph at location 1000, then the kerning between them might come from location 500. 

    But kerning at location 500 was only designed to work for glyphs at location 500, not between ones glyph from 0 and one from 1000. 

    This is a hypothetical example but it shows real consideration. 

    Positioning of glyphs that come from different locations may need to be different than the positioning that happens in the locations between them. 

    Two Germans will speak German to each other. Two Spanish people will speak Spanish. And two French people will speak French. 

    France lies between Germany and Spain — but this doesn't mean that the best language in which a German can communicate with a Spanish person is French. 

    In fact it's not at all clear what the best language should be. I hope my analogy makes sense :) 

    An even better example is with colors. You may dress in all things green, all things blue or all things red. But if you put on a green t-shirt and red shoes, it does not automatically mean that your trousers should be blue, even though blue is between red and green on the color spectrum. 

    Software developers must know exactly how a system will work and must implement it exactly. There is very little room for "maybies". 

    Implementing a system that will deliver sensible results between different instances of a variable font is difficult, because it's not at all obvious which results would be sensible. 

  • Thanks for detailed response Adam. My understanding then is that 'font-level' variation is the key aspect for me to remember. Small caps and other OT features will remain as additional glyphs which are varied along with all the other characters in the font.
  • ... So Monospace? :smile:
  • I know you're joking but I think nobody will seriously consider a proposal and then implement it if it has very serious limitations as to what types of fonts it can be used with.

    Sure, there will always be some limitations (for example, today variable fonts work with TrueType outlines and PostScript outlines but not SVG outlines, and that's accepted as a compromise). But if some functionality requires serious engineering work, it has much bigger chances of succeeding if it can solve a variety of problems rather than just one or two. 

    Again, I myself would welcome this development (so that variation can somehow become useful on the sub-font, inter-glyph level) but I know it's quite hard, so it'll take a lot of time to even formulate an initial proposal. And it works require someone to actually come up with a specific proposal (that would propose how exactly it should work). 
  • One can find a lot cases that will not work (as Adam has shown). But that is true with a lot different things, too. Like all programming languages.

    But there are a lot of very interesting use cases that don’t have those problem. Like having variable length iMatra. Or a script typeface with a final swash that is always as long as the whole word. Both scenarios would need some form of context based axis values. 
  • Oh, of course! I'm not saying "let's not do it". I could list many many examples where it would be useful.

    The classic example is subscripts and superscripts, and many other uses similar to how people would want to use the "smart components" in Glyphs. Also mathematics, small caps, Arabic kashidas, and generally glyphs that could stretch to achieve better justification.

    I would be among the first to applaud this, I'm just saying that coming up with a technically sound proposal isn't trivial because there are many caveats that have to be considered. :)