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

BezPath's f64 lose precision after cast to f32 when using ReverseContourPen #640

Closed
anthrotype opened this issue Sep 29, 2023 · 4 comments
Closed

Comments

@anthrotype
Copy link
Member

fontc uses write-fonts' ReverseContourPen to reverse glyph contour's direction (for various reasons), doing something like this:

/// Reverse the winding direction of the path.
fn reverse_direction(path: &BezPath) -> Result<BezPath, Error> {
    let mut bez_pen = BezPathPen::new();
    let mut rev_pen = ReverseContourPen::new(&mut bez_pen);
    write_to_pen(path, &mut rev_pen);
    rev_pen
        .flush()
        .map_err(|e| Error::ContourReversalError(format!("{e:?}")))?;
    Ok(bez_pen.into_inner())
}

fontc stores glyph contours as kurbo::BezPath, which internally store coordinates as f64.

Because the font-types' Pen trait (which ReverseContourPen implements) uses f32 instead of f64, the coordinates get rounded and lose precision. You may argue 32-bit floats should be enough..

However, when I tried to use the ReverseContourPen to implement googlefonts/fontc#174, right before the BezPaths get converted to write-fonts' SimpleGlyphs (using interpolatable_glyphs_from_bezpaths method, which is where the implied on-curve midpoints get pruned), because the f64 are cast as f32, losing precision, I end up getting entirely different implied oncurves than when I convert the BezPath to SimpleGlyphs without reversing them first.

To match exactly fonttools, remember that we ported the Python math.isclose method which is used over there to test if a given point is almost in the middle between two points, and we are even using the same default tolerances as Python's isclose, i.e. rel_tol=1e-9 and abs_tol=0.0 (check write-fonts::util::isclose).

So while we could relax the isclose tolerance, I would rather have a way to pass through the f64 coordinates unrounded and keep the tighter tolerance.

How can we do that? Do we need to make the Pen trait generic over coordinate type? Any help appreciated, thanks

@anthrotype
Copy link
Member Author

You can test my WIP branch where I call ReverseContourPen on all the contours with this googlefonts/fontc#475

running ttx_diff.py on e.g. Oswald.glyphs, you'll notice the number of (no-longer-implied) oncurve points in the glyf table increases dramatically

@dfrg
Copy link
Member

dfrg commented Sep 29, 2023

I believe the initial proposal for the Pen trait was generic over coordinate type but that was deemed to be "premature abstraction" at the time. Maybe we should revisit?

@rsheeter
Copy link
Collaborator

Why not just make pen f64?

@anthrotype
Copy link
Member Author

this is no longer an issue because we now no longer use a pen to do the contour reversal but rely on the new kurbo::BezPath::reverse_subpaths method

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

3 participants