-
Notifications
You must be signed in to change notification settings - Fork 680
Add hb_ot_layout_lookup_collect_glyph_alternates()
#5367
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
base: main
Are you sure you want to change the base?
Conversation
To collect all glyph mapping from SingleSubst or AlternateSubst lookups in one call. Needed by FreeType autohinter for performance. New API: +hb_ot_layout_lookup_collect_glyph_alternates()
src/hb-ot-layout.cc
Outdated
* will encode those mappings in a certain encoding: | ||
* If G is the glyph id, and A0, A1, ..., A(n-1) are the alternate glyph ids, | ||
* the mapping will contain the following entries: (G + (i << 24)) -> Ai | ||
* for i = 0, 1, ..., n-1. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! However, what I really want is the ability to iterate over all lookup indices, using the same hb_map_t
object for each call so that HarfBuzz collects the data cumulatively (i.e., the mapping
argument of hb_ot_layout_lookup_collect_glyph_alternates
should be of type INOUT
).
What about the following scheme: If glyph G
has alternates A1
, A2
, ..., A(n)
, use the following mapping:
G -> N << 24
G + (1 << 24) -> A1
G + (2 << 24) -> A2
...
G + (N << 24) -> A(n)
Now assume three lookup tables X
, Y
, and Z
, with the following data.
X: G -> G1 (SingleSubst)
Y: G -> G2 (SingleSubst)
Z: G -> G3, G4 (AlternateSubst)
After calling hb_ot_layout_lookup_collect_glyph_alternates
on X
, the mapping would contain
G -> G1
after calling the function again on Y
, the mapping becomes
G -> 2 << 24
G + (1 << 24) -> G1
G + (2 << 24) -> G2
and after calling on Z
we have
G -> 4 << 24
G + (1 << 24) -> G1
G + (2 << 24) -> G2
G + (3 << 24) -> G3
G + (4 << 24) -> G4
After processing all lookups I could then iterate over the mapping, ignoring all mapping keys larger than or equal to 1<<24, which I would only look up on demand.
Such a scheme, however, would only fly if both keys and values of the mapping are 64bit integers – it would be tedious otherwise to handle an 'overflow' of alternates. Of course, for current FreeType it would work just fine if we used the lower 16 bits for glyph indices and the upper 16 bits for enumerating alternatives...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correction: this scheme is better.
G -> A1 + (N << 24)
G + (1 << 24) -> A2
G + (2 << 24) -> A3
...
G + ((N-1) << 24) -> A(n)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to implement this using two separate maps: one mapping gid to number of alternates. Another, mapping gid to all it's alternates using the proposed encoding of mine. That should address your concerns.
I think I want to stick with 24bit gids and 256 alternates per gid. The extra code to collect more variations of glyphs with more than 256 alternates is about 30 lines of code I think... But also something that I think can completely be ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, and yes, I agree that the case of having more than 256 alternates could either be ignored (with a warning, say) or implemented in a way that doesn't have to be efficient.
However, it's still not clear to me how I should use your suggested new function. Could you please provide some pseudo-code how iterating over all lookup tables would look like to construct the reverse cmap table?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In pseudocode:
lookups = hb_set_create();
for feature_tag in requested_features:
add feature_tag's lookups to lookups
glyph_alternates_count = hb_map_create();
glyph_alternates = hb_map_create();
for lookup_index in lookups:
hb_ot_layout_lookup_collect_glyph_alternates(face, lookup_index, glyph_alternates_count, glyph_alternates);
for gid, count in glyph_alternates_count:
for (unsigned i = 0; i < count; i++)
{
hb_codepoint_t key = gid | (i << 24);
hb_codepoint_t alternate = glyph_alternates.get(key);
printf("gid %u alternate %u\n", gid, alternate);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You combine that with cmap and you get your reverse cmap.
I pushed a new change, which is now causing gcc-14 warnings that I think are spurious. We've seen similar warnings before from gcc. Clang is happy with this code.
|
Do you want to have this for the next release? |
I'll see if I can finish it before Monday. But I have notes re VARC and hvgl to write (in a doc)... |
No description provided.