googlefonts / fontations

Reading and writing font files
Apache License 2.0
395 stars 26 forks source link

Can't `to_owned_table` a `glyf` table? #1253

Closed simoncozens closed 3 days ago

simoncozens commented 6 days ago

The write-fonts documentation suggests that I should be able to do:

use write_fonts::{from_obj::{FromTableRef, ToOwnedTable}, tables::{glyf::Glyf, name::Name}};

let name: Name = font.name().unwrap().to_owned_table(); // This works
let glyf: Glyf = font.glyf().unwrap().to_owned_table(); // This doesn't
the trait bound `write_fonts::tables::glyf::Glyf: write_fonts::from_obj::FromTableRef<read_fonts::TableRef<'_, read_fonts::tables::glyf::GlyfMarker>>` is not satisfied

I'm presuming that this is because glyf is Special thanks to the whole glyf/loca dance. But I'm not clear how I'm supposed to modify a glyf table. (Needed to remove TTF hinting instructions.)

cmyr commented 5 days ago

Yea, that's annoying.

Realistically if you're modifying glyf I presume you're also modifying loca?

I think the best approach here will be to add a method to glyf that iterates all the contained glyphs, which would then let us handle this sanely.

(edit: I'll take this, to be clear)

simoncozens commented 5 days ago

Thank you!

cmyr commented 5 days ago

Okay so i've run into an interesting issue here, in trying to iterate over glyphs without using loca

I presume I'm missing something here, but it isn't immediately obvious what it is...

simoncozens commented 5 days ago

I would expect to have a method on a glyf table which hands me back a Vec of owned Glyphs, and another in write-fonts which builds glyf and loca from such a Vec.

cmyr commented 5 days ago

right, my problem is that it isn't actually clear to me that you can unambiguously parse glyphs out of the glyf table without loca, since you don't know if the glyph data is padded to a two-byte offset, or not?

for constructing the table we have GlyfLocaBuilder.

rsheeter commented 5 days ago

trying to iterate over glyphs without using loca

You aren't meant to do this :)

cmyr commented 5 days ago

right, but is it possible? it seemed like it would be except for this funny padding issue. If it isn't possible at all than we can't really address this issue, unless we do something like fundamentally require the loca table to be passed into glyf at parse time (which might not be the worst idea in the world? idk)

simoncozens commented 5 days ago

Well, we already do that. But all I'm asking is for a way to create an owned set of Glyphs from an existing glyf/loca pair. And we can already parse glyf and loca, so all the pieces are there.

simoncozens commented 4 days ago

Maybe all I need is

            let owned_glyphs: Vec<Glyph> = (0..glyph_count)
                .map(GlyphId::from)
                .flat_map(|gid| loca.get_glyf(gid, &glyf))
                .flatten()
                .map(|g| Glyph::from_table_ref(&g))
                .collect();
simoncozens commented 4 days ago

Argh, now I've got some owned Glyphs, I realise I can't do anything with them because:

I wonder if this is an interface optimised for writing font compilers. :-)

Would you take a PR which exposes contours and instructions so they can be manipulated directly, or am I missing the reason why things are the way they are?

cmyr commented 4 days ago

I don't think there is an strong reason for those fields to be private, I think we just haven't really been dealing with your use case until now, a PR sounds fine. Please rename _instructions to instructions, and you might also need to add some API to Contour to make it useable...

dfrg commented 4 days ago

I believe klippa already has efficient code for stripping hints. Maybe some of this could be moved to write-fonts or exposed in some way to be accessible outside of subsetting.

simoncozens commented 4 days ago

That's helpful, but it's not just about stripping hints - currently there's no way to manipulate Glyphs in general (e.g. decomposing components). I'll try a PR.