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

Some valid component arrangements lead to 'interpolation-incompatible paths' error #1115

Closed
Hoolean opened this issue Nov 14, 2024 · 9 comments
Assignees
Labels
bug Something isn't working

Comments

@Hoolean
Copy link
Contributor

Hoolean commented Nov 14, 2024

Hello!

At Dalton Maag we've tried experimentally compiling one of our larger library fonts with the latest fontc, and have got an 'interpolation-incompatible paths' error for an arrangement of contours and components that should be valid after decomposition, and which fontmake accepts.

Reproducing

The original font is proprietary, and so we've made an independent minimal reproducer to share here, whose UFOs can also be used as the basis for an integration test if convenient :)

from fontTools.designspaceLib import (
    AxisDescriptor,
    DesignSpaceDocument,
    InstanceDescriptor,
    SourceDescriptor,
)
from fontTools.misc.transform import Identity, Transform
from ufoLib2 import Font
from ufoLib2.objects import Component, Contour, Point

# Create designspace with weight axis
doc = DesignSpaceDocument()
doc.addAxis(
    AxisDescriptor(tag="wght", name="Weight", minimum=400, maximum=700, default=400)
)

# Create the same glyph arrangement in two sources, one with a component offset.
for style, weight, transform in [
    ("Regular", 400, Identity),
    ("Bold", 700, Transform(dx=100)),
]:
    ufo = Font()

    # Make a glyph with contours, and two components.
    outer = ufo.newGlyph("outer")
    outer.contours.append(Contour([Point(x=0, y=0)]))
    outer.components.append(Component("inner", transformation=transform))
    outer.components.append(Component("inner"))

    # Glyph with minimal contours for use as a component.
    inner = ufo.newGlyph("inner")
    inner.contours.append(Contour([Point(x=10, y=10)]))

    ufo.save(f"{style}.ufo", overwrite=True)

    doc.addSource(SourceDescriptor(path=f"{style}.ufo", location={"Weight": weight}))
    doc.addInstance(InstanceDescriptor(styleName=style, location={"Weight": weight}))

doc.write("OuterInner.designspace")

NOTE: The same error occurs with more points - the outlines above have just been shrunk to keep the test case small

Full error

[... ThreadId(1) fontc ERROR] 'outer' has interpolation-incompatible paths
error: process didn't exit successfully: `...\fontc.exe .../OuterInner.designspace` (exit code: 1)
@rsheeter rsheeter added the bug Something isn't working label Nov 14, 2024
@rsheeter
Copy link
Contributor

rsheeter commented Nov 14, 2024

Thank you for the report! Edit: I see the problem, we have a bad assumption that nobody would reuse the same component with the same transform twice.

@rsheeter rsheeter self-assigned this Nov 14, 2024
rsheeter added a commit that referenced this issue Nov 15, 2024
github-merge-queue bot pushed a commit that referenced this issue Nov 15, 2024
@rsheeter
Copy link
Contributor

Could you retry to see if #1122 helps?

@Hoolean
Copy link
Contributor Author

Hoolean commented Nov 20, 2024

Thanks for the swift patch Rod!

I'm afraid we have strange results... the issue initially appeared fixed, but I then saw fontc crash with the original error during a later invocation.

To rule out an environment issue, I then invoked the compilation identically a consecutive 8 times, while making no other changes; this worked 6/8 times but failed 2/8 times with the original issue, and so I fear there is something non-deterministic happening now:

$ cargo run -- Font.designspace --skip-features
(pass)
$ cargo run -- Font.designspace --skip-features
(pass)
$ cargo run -- Font.designspace --skip-features
(pass)
$ cargo run -- Font.designspace --skip-features
[... ThreadId(1) fontc ERROR] '...' has interpolation-incompatible paths
$ cargo run -- Font.designspace --skip-features
(pass)
$ cargo run -- Font.designspace --skip-features
(pass)
$ cargo run -- Font.designspace --skip-features
(pass)
$ cargo run -- Font.designspace --skip-features
[... ThreadId(1) fontc ERROR] '...' has interpolation-incompatible paths

This testing used the latest commit on main (20d1e7d) and the original proprietary sources; might there be something non-deterministic happening with component order? 🔎

@Hoolean
Copy link
Contributor Author

Hoolean commented Nov 20, 2024

(over 10 invocations I can't reproduce with the minimal reproducer anymore, so the non-determinism may only become likely to cause trouble with a larger number of contours, glyphs or designspace locations)

@rsheeter
Copy link
Contributor

Thanks, that's a good clue. Doubtless I did something silly with a hashset in my quick fix :)

@Hoolean
Copy link
Contributor Author

Hoolean commented Nov 21, 2024

Cheers again for the deep dive on this one Rod :) One extra clue maybe, I noticed that Readex Pro has been alternatively hopping in and out of the 'fontc failures' list on fontc_crater with the same error since the fix, in case this is useful for a reprod too

@rsheeter
Copy link
Contributor

rsheeter commented Dec 3, 2024

Pardon the delay, lot of OOO for Thanksgiving. I'm hoping #1150 helps?

@Hoolean
Copy link
Contributor Author

Hoolean commented Dec 5, 2024

No worries at all, thanks for the fix! I'll test straight away

@Hoolean
Copy link
Contributor Author

Hoolean commented Dec 5, 2024

As race conditions are tricksy I ran fontc double the number of times as before (16) to look for crashes; there are none now, and so I am confident that this is fixed for the original font 🍾 Thanks again Rod + Colin!

@Hoolean Hoolean closed this as completed Dec 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants