Skip to content

Also interpolate components#1652

Merged
cmyr merged 4 commits into
mainfrom
also-interpolate-components
Sep 25, 2025
Merged

Also interpolate components#1652
cmyr merged 4 commits into
mainfrom
also-interpolate-components

Conversation

@cmyr

@cmyr cmyr commented Sep 24, 2025

Copy link
Copy Markdown
Member

On top of #1650, this adds the ability to interpolate components with simple transforms.

This doesn't handle complex transformations, because I'm not sure how we should be doing that.

More generally, I have some concerns with the overall control flow in this file. There's a lot going on, and there are lots of moving pieces.

  • it's hard to figure out the order in which things should be called. Some stuff, like inlining non-export glyphs, has to happen all the time.
  • other stuff happens based on flags or other conditions.
  • it's not clear what conditions are expected to be true of an IR glyph. For instance, is it okay for an IR glyph to have instances with a different 'shape', e.g. where one instance has a contour and the other has a component? Or for contours to have different numbers of points? If we knew this was already validated, other work would be simpler.
  • it would be nice if we had clear expectations about things like intermediate layers, so that we could get all those things normalized ahead of time. For instance: can we figure out all of the glyphs that are going to get decomposed, and ensure ahead of time that the composite & component instances are compatible? (I guess not, thinking out loud, since we might not want to actually modify the component glyph?)

@anthrotype

Copy link
Copy Markdown
Member

For instance, is it okay for an IR glyph to have instances with a different 'shape', e.g. where one instance has a contour and the other has a component? Or for contours to have different numbers of points?

No, and no. I think we have a CheckedGlyph somewhere, but maybe that was in fontbe..

@anthrotype

Copy link
Copy Markdown
Member

can we figure out all of the glyphs that are going to get decomposed, and ensure ahead of time that the composite & component instances are compatible? (I guess not, thinking out loud, since we might not want to actually modify the component glyph?)

if we are going to decompose a glyph in the end, then yes. But if a glyph stays composite then it's ok for it be 'sparse', i.e. have more or fewer locations than any of its component glyphs, so you don't want to do it upfront regardless

@anthrotype

anthrotype commented Sep 25, 2025

Copy link
Copy Markdown
Member

This doesn't handle complex transformations, because I'm not sure how we should be doing that.

that's a good point.

Currently in ufo2ft.instantiator we rely on fontMath for the actual interpolation. By default fontMath.MathGlyph just multiplies all the component transform values by the given interpolation scalar.. there's an option scaleComponentTransform=True that if set to False it restricts the interpolation to the xOffset/yOffset and leaves the 2x2 alone, however ufo2ft doesn't use it at the moment:

https://github.com/robotools/fontMath/blob/99c3047efbba68134bd0b8617e504330d5c5bdce/Lib/fontMath/mathGlyph.py#L79-L83
https://github.com/googlefonts/ufo2ft/blob/d66583741a09ec93fdc3ec53bf0f961e5aac5d1e/Lib/ufo2ft/instantiator.py#L1034

which means when static interpolated UFO instances are generated by fontmake, the whole component.transform gets interpolated... (wrongly?)
fontMath also has a fancier MathTransform class which first decomposes the transform matrix into offset, scale and rotation factors and interpolates each, but it isn't used anywhere...
https://github.com/robotools/fontMath/blob/master/Lib/fontMath/mathTransform.py

but wait.. having written all that, that's all tangential to our problem here, we are dealing with variable fonts (not interpolated UFO instances to be built into statics, which we don't currently support anyway). In VFs, components in all masters must must have the same 2x2 transform, can only vary in the X/Y offset and we already make sure we decompose those, so you shouldn't ever come acress those in this code if we have properly decomposed them already.. Have we not?

Comment thread fontir/src/glyph.rs Outdated
@cmyr cmyr force-pushed the non-standard-model branch from 426d86c to c240c6b Compare September 25, 2025 15:03
@cmyr

cmyr commented Sep 25, 2025

Copy link
Copy Markdown
Member Author

but wait.. having written all that, that's all tangential to our problem here, we are dealing with variable fonts (not interpolated UFO instances to be built into statics, which we don't currently support anyway). In VFs, components in all masters must must have the same 2x2 transform, can only vary in the X/Y offset and we already make sure we decompose those, so you shouldn't ever come acress those in this code if we have properly decomposed them already.. Have we not?

not in all cases. For instance we flatten export glyphs before we do anything else, which means 2x2 transforms are not yet decomposed. Should decomposition happen first?

Base automatically changed from non-standard-model to main September 25, 2025 15:08
@anthrotype

Copy link
Copy Markdown
Member

oh right. Hm, ufo2ft preProcessor similarly decomposes those skipExportGlyphs before doing any subsequent filter, including the decomposition of components with non-matching 2x2...

its SkipExportGlyphsIFilter (where "I" stands for "interpolatable" filter, zipping same-named glyph across all sources) uses the ufo2ft.instantiator to generate instances for missing components so... yeah what I said earlier about fontMath applies here too for VFs, not just to the static build pipeline...

@cmyr cmyr force-pushed the also-interpolate-components branch from 993dfa3 to 3afbd88 Compare September 25, 2025 15:15
@anthrotype

Copy link
Copy Markdown
Member

I think the problem of treating all the transform values as something that can be linearly interpolated would only really be a problem if a component contains some rotation or skew, if it's only scaled and/or translated (the most common scenario) it should be ok..

@cmyr

cmyr commented Sep 25, 2025

Copy link
Copy Markdown
Member Author

I think the problem of treating all the transform values as something that can be linearly interpolated would only really be a problem if a component contains some rotation or skew, if it's only scaled and/or translated (the most common scenario) it should be ok..

I definitely agree that it should be fine in the common case, but I'm trying not to ignore the edge cases.

@anthrotype

Copy link
Copy Markdown
Member

fonttools now has a DecomposedTransform that can decompose a 2x3 affine Transform into its separate translate, rotation, scale and skew components.. so technically we could have ufo2ft and fontMath do it right, by lerp'ing each of these independently and recomposing. I'll file an issue in ufo2ft

Comment thread fontir/src/glyph.rs Outdated

/// Interpolate components (specifically their transforms)
///
/// Matching varLib, we will just blindly interpolate the scalar values, which

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Matching varLib, we will just blindly interpolate the scalar values, which
/// Matching ufo2ft, we will just blindly interpolate the scalar values, which

varLib errors out if component don't have matching 2x2, they are already decomposed by the time they reach varLib. It's in ufo2ft.instantiator that this blind element-wise interpolation of 2x3 affine transformations happens, through fontMath technically.

you could link googlefonts/ufo2ft#949

However interpolation of components only works when they have trivial
(translation-only) transforms. If they have anything more fancy, we will
need to decompose the components first?
Components need to be defined at each location in order for us to be
able to generate contours for them.
@cmyr cmyr force-pushed the also-interpolate-components branch from 74e8270 to c68fd5b Compare September 25, 2025 16:46
Instead of just dropping complex transforms on the floor.

This matches fonttools.
@cmyr cmyr force-pushed the also-interpolate-components branch from c68fd5b to c7c16a5 Compare September 25, 2025 16:54
@cmyr cmyr added this pull request to the merge queue Sep 25, 2025
Merged via the queue into main with commit 3a77997 Sep 25, 2025
12 checks passed
@cmyr cmyr deleted the also-interpolate-components branch September 25, 2025 17:00
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

Successfully merging this pull request may close these issues.

2 participants