Fixes#2081
Many fonts have a bad ligature for "fl", "fi", or "st". We previously
maintained a list of such fonts in quirks.zig. However, these are so
common that it was suggested we do something more systematic and this
commit is that.
This commit changes our text run splitting algorithm to always split on
`fl`, `fi`, and `st`. This will cause some more runs for well behaved
fonts but the combination of those characters is rare enough and our
caching algorithm is good enough that it should be minimal overhead.
This commit renders our existing quirks fonts obsolete but I kept that
logic around so we can add to it if/when we find other quirky font
behaviors.
Some CoreFoundation objects, such as those produced by CoreText, have
expensive callbacks that run when they are released. By offloading the
CFRelease calls to another thread, we can avoid important threads being
blocked by unexpectedly expensive callbacks.
This commit also changes the way that the coretext shaper's run iterator
builds its string. Rather than using a CFMutableString, an ArrayList of
unichars is built which is passed to CFStringCreateWithCharactersNoCopy,
which is a lot more efficient since it avoids all the CoreFoundation
overhead.
Now that we're padding the cells with blanks if we have shaped ligatures
we don't actually know the exact count based on the CoreText APIs, so we
should just dynamically add.
Fixes#1708
Harfbuzz does this automatically. Our tests for harfbuzz test this. We
had a todo in CoreText to mimic this but wasn't sure if it was useful.
Turns out, it is important (see bug!)
Fixes#1664
I previously asserted that we got exactly one run from CoreText because
I assumed that our run iterator was perfectly splitting runs for
CoreText. This assumption appears to be false and that seems okay.
The test case in this commit produces two runs that are directly next to
each other and there's no downside to simply iterating over them. So
this commit changes to iterate over the runs.
Up to this point, every font I've experienced with ligatures has
replaced the codepoints that were replaced for combining with a space.
For example, if a font has a ligature for "!=" to turn it into a glyph,
it'd shape to `[not equal glyph, space]`, so it'd still take up two
cells, allowing us to style both.
Monaspace, however, does not do this. It turns "!=" into `[not equal
glyph]` so styles like backgrounds, underlines, etc. were not extending.
This commit detects multi-cell glyphs and inserts synthetic blank cells
so that styling returns. I decided to do this via synthetic blank cells
instead of introducing a `cell_width` to the shaper result because this
simplifies the renderers to assume each shaper cell is one cell. We can
change this later if we need to.
Annoyingly, this does make the shaper slightly slower for EVERYONE to
accomodate one known font that behaves this way. I haven't benchmarked
it but my belief is that the performance impact will be negligible
because to figure out cell width we're only accessing subsequent cells
so they're likely to be in the CPU cache and also 99% of cells are going
to be width 1.