-
Notifications
You must be signed in to change notification settings - Fork 313
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
Implement fallback font support to HarfBuzz sample #635
Implement fallback font support to HarfBuzz sample #635
Conversation
b852f53
to
fea8921
Compare
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.
Very nice, thanks a lot for staying around to further improve the sample and font engine! :)
This works for me, and the code looks very reasonable. I didn't go into all the details, I hope that we at some point can de-duplicate the reused code and get the font engine into Core. At that point I will go a bit more detailed into it.
It seems like the fallback logic was mostly written from scratch. I wondered if there is something about Harfbuzz that makes it different from the one in our existing FreeType font engine in Core? Do you think we in principle could share the same fallback code?
hb_direction_t text_direction = hb_script_get_horizontal_direction(script); | ||
if (text_direction == HB_DIRECTION_INVALID) | ||
// Some scripts support both horizontal directions of text flow; default to left-to-right. | ||
text_direction = HB_DIRECTION_LTR; |
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 to get away from hard-coded values :)
The main issue was that the existing font engine uses Unicode character codepoints to identify glyphs, whereäs HarfBuzz uses glyph indices within the OpenType/TrueType data. This is because a single character can map to multiple glyphs (since a single character can be shaped differently depending on where it is in a word). In the initial sample (before this PR), I made all of the function parameters and class members use glyph indices instead of character codepoints. This worked fine, but I had to change it if we wanted to support fallback glyphs. A glyph index of zero is defined within the OpenType standard to represent a character that is unsupported by the font. This means that the character codepoint is the only way of identifying an unsupported character (since they all have the same glyph index of zero). Therefore, I needed two ways to identify a glyph: its index and its character codepoint. In the For the Other than that, I ensured using the preëxisting fallback code where possible (such as in |
Thanks a lot for elaborating, that's very helpful. It makes a lot of sense to me now. |
Adds support for fallback fonts to the HarfBuzz text shaping sample. Resolves #634.
To implement this, I had to keep track of the original character codepoint alongside the glyph bitmaps (since the glyph index is always zero for unsupported glyphs, this is how they are able to be disambiguated). Each font now has a lookup table for fallback glyphs that maps each unsupported character to their respective bitmap, as well as functions to append and retrieve glyphs from fallback fonts.
For the font layers, the logic remained mostly the same. When generating a texture, they now iterate through both the regular and fallback glyphs of a font. The rectangle ID is now represented as a bit-shifted combination of the glyph index and character codepoint (using sixty-four bits). I found this to be the most elegant solution that supports mapping multiple glyph indices to character codepoints (and vice versa), and it only needs one texture layout. However, it did require me to copy all of the texture layout files to the sample just to change the type of the rectangle ID from a regular integer to a
uint64_t
. This won't really be an issue when integrating this into RmlUi proper, since the texture layout files can just be edited in situ.