googlefonts / oxidize

Notes on moving tools and libraries to Rust.
Apache License 2.0
173 stars 7 forks source link

Font editor perspectives #21

Open justvanrossum opened 2 years ago

justvanrossum commented 2 years ago

I just spoke to @chrissimpkins, and shared some loose thoughts about "faster font compilation" in the context of a font editor, and he suggested that I post here, as you are talking about use cases.

(I follow this repo only superficially, as the details of Rust table implementation strategies are beyond my expertise.)

Premise: A font editor would benefit from showing the user correctly shaped live previews.

FontGoggles attempts to do this as quickly as possible when previewing UFOs, using the following strategy:

While this is a lot faster than compiling a full font with fontmake, there are still two bottlenecks:

So: specialized (Rust-based?) tools for those two tasks would be incredibly useful.

For a font editor with in-memory data, things will look a little different:

With the currently available tools, we have to go via .fea to get data that HarfBuzz can use. This gives us a double bottle-neck:

My final thought here is that a superfast shaper isn't a requirement, but a shaper that can more efficiently work from live data (for example kerning and anchors) is what's really needed.

Using Rust-based tools will surely make many things much faster, but to me there is possibly more to gain with a clever (I know I'm hand-waving) system that can shape more directly from font/glyph source data, looking only at the data that is relevant for the string being displayed, without having to go via TWO intermediate formats (.fea and OTL tables).

The other thing that could be beneficial for a font editor is incremental compilation to a full font: when I edit a single glyph of a single master of a 50,000-glyph variable CJK font, it shouldn't require recompilation of the whole thing.

cmyr commented 2 years ago

So this is basically the original motivation that set me down on this path, and remains one of the major goals. I have other dreams (like a step-through debugger for shaping, where it can show each rule that is applied, and its source) but I am definitely keeping this case in mind.

Incremental compilation is also definitely something nice to have; ideally that can be a layer on top of the general compilation tools.

justvanrossum commented 2 years ago

If providing fast interactive shaping is a goal, then good Rust ⟷ Other Languages interop should be part of the goals, too.

Rust is awesome for specific low level fastness, but not so much for high level orchestrating of complex processes, where people with lower CompSci skills still want to (and deserve to be able to) customize.

madig commented 2 years ago

(@cmyr regarding a step-by-step non-interactive shaper, see http://corvelsoftware.co.uk/crowbar/)

adrientetar commented 1 year ago

One other topic when it comes to font editors is efficient interoperability, since they might be written in different languages. e.g. do I need to write a file to disk to feed to the compiler, or can I provide the input data over pipes, or use a C API?

rsheeter commented 1 year ago

do I need to write a file to disk to feed to the compiler

At time of writing, yes.

can I provide the input data over pipes, or use a C API?

Not yet, but I don't see why not. Wrt pipes, what would you expect to pipe? - a standalone .glyphs file makes sense but UFO+designspace doesn't seem to lend itself as well to piping. Or perhaps you had some other input in mind?

rsheeter commented 1 year ago

Or file an issue against https://github.com/googlefonts/fontmake-rs explaining what you'd like to do?

schriftgestalt commented 9 months ago

adding my 2 cents:

There are two use cases:

The two most expensive operations I encounter in Glyphs:

The current state of external compilers (like fontc or fontmake) adds the parsing and translation of the source file.

One solution to cut down most of the above could be to expose the internal representation (by an API/callbacks) that the editor app could build up data (instead of the source parser). So the editor tells the compiler: "Here are some outlines", "Here is a list of kerning pairs", "Here is another kerning pair", "Here is some fea-code" …

That could be done by a direct c style API or by pipes (potentially slower? More error prone?)

We are in the works for feaKit: it will get an API that lets me give it some fea code (a lookup or a feature) one at a time or, more importantly lets me write the GPOS lookups directly into the internal representation. That has two big advantages. It is much faster and, if done right lets me incrementally update things (e.g. a changed kerning pair).

And one important benefit: it can give much more precise errors. Because the context were that data came from is much clearer.

rsheeter commented 9 months ago

One solution to cut down most of the above could be to expose the internal representation

An in memory translation to what fontc reads .glyphs files into (here) should be pretty quick, no need to touch disk or parse a source file.

feaKit [...] lets me write the GPOS lookups directly into the internal representation

Ha, us too. fea-rs is learning this trick so fontc can avoid generating strings to parse.

anthrotype commented 9 months ago

An in memory translation to what fontc reads .glyphs files into (here)

IIUC, Georg was referring to the fontc IR (fontir/src/ir.rs) proper, not the glyph-reader/font.rs that we parse the plist into. So basically the font editor would do the job of glyphs2fontir themselves, skipping not just the plist parsing but the glyphs=>IR itself and somehow produce IR directly to feed fontc

rsheeter commented 9 months ago

IIUC, Georg was referring to the fontc IR (fontir/src/ir.rs) proper, not the glyph-reader/font.rs that we parse the plist into

That was my understanding also but I think that bypasses things we do want to happen.

schriftgestalt commented 9 months ago

We should be able to find a level where it makes sense to hand over the data.