go-text / typesetting

High quality text shaping in pure Go.
Other
88 stars 11 forks source link

fontscan: expose footprint and means of registering existing faces #80

Closed whereswaldon closed 1 year ago

whereswaldon commented 1 year ago

~This commit allows already-parsed fonts to be inserted into the fontmap from an application. In order to do this with valid rune coverage maps, I needed to export a way for applications to construct Footprints so that the footprint could be provided alongside the font (assuming that the loader is no longer available). I'm open to feedback on whether this is a good idea.~

~@benoitkugler I found that Gio needed a means of registering already-parsed fonts (loaded from embedded font files) into the fontmap, so this is my stab at making that work. Let me know what you think about the approach.~

I've rewritten this to avoid exposing implementation details. Now there's simply an AddFace method that inserts an existing face and its metadata.

Gio uses this to register already-in-memory fonts so that they can be considered during the font selection process. Additionally, frequently Gio applications do not specify a font family during shaping, relying on the fact that manually loaded faces will be selected in this case.

I've implemented selecting from manually-loaded faces as a fallback for when the substitution process fails. It seems like it doesn't violate the CSS spec in an important way (this decision is arbitrary, but it is also useful).

@benoitkugler Does this seem like a reasonable change?

benoitkugler commented 1 year ago

I'm not a big fan of exposing Footprint, since it is an implementation detail of the library.

An alternative idea would be to add a Metadata method directly on the Face. The cmap and widths are already available, so it would only require a few bytes to store the aspect. Then the fontmap could internally build the footprint, still without requiring a face loader.

We would keep the current metadata package for performance.

benoitkugler commented 1 year ago

I'm not a big fan of exposing Footprint, since it is an implementation detail of the library.

An alternative idea would be to add a Metadata method directly on the Face. The cmap, widths and family names are already available, so it would only require a few bytes to store the aspect. Then the fontmap could internally build the footprint, still without requiring a face loader.

We would keep the current metadata package for performance.

whereswaldon commented 1 year ago

@benoitkugler I've taken another stab at this. I think this looks cleaner. Please let me know your thoughts on the behavior change.

benoitkugler commented 1 year ago

I've implemented selecting from manually-loaded faces as a fallback for when the substitution process fails. It seems like it doesn't violate the CSS spec in an important way (this decision is arbitrary, but it is also useful).

@benoitkugler Does this seem like a reasonable change?

Nicely done, this seems nice to have indeed.

whereswaldon commented 1 year ago

@benoitkugler Are you happy for this to merge into #63, or do you have more review to do first?

benoitkugler commented 1 year ago

@benoitkugler Are you happy for this to merge into #63, or do you have more review to do first?

Done, thank you

andydotxyz commented 1 year ago

I like the solution that was reached here. Is it correct that the order in which UseSystemFonts, AddFont etc are called will determine the lookup order?

whereswaldon commented 1 year ago

I like the solution that was reached here. Is it correct that the order in which UseSystemFonts, AddFont etc are called will determine the lookup order?

The fallback mechanism that I introduced here is only tried if zero system fonts matched. I think the only realistic way for that to happen is if you didn't load the system fonts or if you simply don't have system fonts covering whatever rune you're trying to resolve.

The order in which AddFont and AddFace are invoked does determine the order in which their faces will be tried in such a case. I believe you'll get the same results no matter when you call UseSystemFonts.

andydotxyz commented 1 year ago

I like the solution that was reached here. Is it correct that the order in which UseSystemFonts, AddFont etc are called will determine the lookup order?

The fallback mechanism that I introduced here is only tried if zero system fonts matched. I think the only realistic way for that to happen is if you didn't load the system fonts or if you simply don't have system fonts covering whatever rune you're trying to resolve.

The order in which AddFont and AddFace are invoked does determine the order in which their faces will be tried in such a case. I believe you'll get the same results no matter when you call UseSystemFonts.

Yeah that sounds sensible thanks. I wonder if this needs to be documented in the overall PR as it's not completely obvious from the API.

whereswaldon commented 1 year ago

I've pushed a commit to font-scan documenting this.