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

[fontscan] Better font resolution #178

Merged
merged 16 commits into from
Jan 14, 2025
Merged

[fontscan] Better font resolution #178

merged 16 commits into from
Jan 14, 2025

Conversation

benoitkugler
Copy link
Contributor

Hi,

This PR aims at providing a better font resolution, especially in the fallback case (where the family asked by the user do not support the text runes).

The main changes (inspired by fontconfig) are :

  1. Implement more precise family substitution, by splitting the added family in two parts : "strong" and "weak". The "strong" ones will be tried before script fallback (see below), the "weak" ones after.
  2. Merge the fallback fonts selected by script into the family fallback.
  3. Support language based family substitutions : for now, this is implemented by mapping scripts to language (which is not optimal but is simpler to begin with)

This is a breaking change, since the shaping.Fontmap interface now requires to be script aware (via the added method SetScript). The two defaults implementations are updated accordingly.

As a side note, the language table is updated (meaning the internal IDs have changed), so that the cache version is bumped.

Thank you for your feedback !

@andydotxyz
Copy link
Contributor

Thanks for doing this. I have a concern about another breaking change and I don't think this does have to be breaking.
Outside of the package in which this is implemented, the usages are SplitByFontGlyphs and Segmenter, both of which have the Input context which is what the Script is extracted from (requiring the breaking SetScript change).

There are two font map implementations and one doesn't use the script, so it seems like a big change on the API level - can we not leave it only on the maps that support it, and make it optional usage and avoid the breaking change?

@benoitkugler
Copy link
Contributor Author

Thanks for doing this. I have a concern about another breaking change and I don't think this does have to be breaking. Outside of the package in which this is implemented, the usages are SplitByFontGlyphs and Segmenter, both of which have the Input context which is what the Script is extracted from (requiring the breaking SetScript change).

There are two font map implementations and one doesn't use the script, so it seems like a big change on the API level - can we not leave it only on the maps that support it, and make it optional usage and avoid the breaking change?

I think that would require to type assert if the fontmap implements the extended interface (with [SetScript]). Perhaps not a big deal.

On the other hand, is there major pain point with the breaking change ? Assuming it is properly tagged.
I expect many users will use the concrete [fontscan.Fontmap] implementation anyhow.

@andydotxyz
Copy link
Contributor

Breaking changes cause people pain, and I feel they should only be done with good reason. Any "go get -u" will break compilation unless every project using this API releases at exactly the same time.

In this example it does not seem to be necessary so it would be good to avoid.

@benoitkugler
Copy link
Contributor Author

benoitkugler commented Jan 12, 2025

Breaking changes cause people pain, and I feel they should only be done with good reason. Any "go get -u" will break compilation unless every project using this API releases at exactly the same time.

Fair enough. I had overlooked the fact that go get -u does not really respect the "minor" / "patch" model we use.

@benoitkugler
Copy link
Contributor Author

69e1db3 uses an optional interface to preserve backward compatibility.

Copy link
Member

@whereswaldon whereswaldon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a couple of very minor documentation issues, but the changeset looks good to me on the whole.

func (fm fontSet) selectByFamilies(crible familyCrible, footprintBuffer *scoredFootprints) []int {
footprintBuffer.reset(fm)
// select the fonts in the fontSet matching [crible], returning their (sorted) indices.
// [buffer1] and [buffer2] are used to reduce allocations.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Outdated parameter names

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was on a previous version of the changes, and has been fixed.

//
// 1 - Only fonts matching exacly one of the [Query.Families] are considered; the list
// is prunned to keep the best match with [Query.Aspect]
// 2 - Fallback fonts are considered, that is fonts with similar families and fonts
// supporting the current script; the list is also prunned according to [Query.Aspect]
// 3 - All fonts matching the current script (set by [FontMap.SetScript]) are tried,
// supporting the current script; the list is also prunned according to [Query.Aspect]4
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Trailing 4 is probably a typo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, fixed.

Copy link
Contributor

@andydotxyz andydotxyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great change, thanks for making it backward compatible!

@benoitkugler benoitkugler merged commit 5e2478f into main Jan 14, 2025
14 checks passed
@benoitkugler benoitkugler deleted the family-subs-precedence branch January 14, 2025 08:25
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

Successfully merging this pull request may close these issues.

3 participants