This is my final set of fixes to the font patcher/icon scaling code. It
builds on #8563 and there's not much reason to pay attention here until
that one has been reviewed (the unique changes in this PR only touch the
two `nerd_font_*` files; the other 8 files in the diff are just #8563).
However, I wanted to make sure the full set of changes/fixes I propose
are out in the open, such that any substantial edits by maintainers
(like in #7953) can take into account the full context.
I think this and the related patches should be considered fixes, not
features, so I hope they can be considered for a 1.2.x release.
This PR fixes some bugs in the extraction of scale and alignment rules
from the `font_patcher` script. Roughly in order of importance:
* Nerd fonts apply an offset to some codepoint ranges when extracting
glyphs from their original font (e.g., Font Awesome) and placing them in
a Nerd Font. Rules are specified in terms of the former codepoints, but
must be applied to the latter. This offset was previously not taken into
account, so rules were applied to the wrong glyphs, and some glyphs that
should have rules didn't get any.
* Previously, the rules from every single patch set was included, but
the embedded Symbols Only font doesn't contain all of them. Most
importantly, there's a legacy patch set that only exists for historical
reasons and is never used anymore, which was overwriting some other
rules because of overlapping codepoint ranges. Also, the Symbols Only
font contains no box drawing characters, so those rules should not be
included. With this PR, irrelevant patch sets are filtered out.
* Some patch sets specify overlapping codepoint ranges, though in
reality the original fonts don't actually cover the full ranges and the
overlaps just imply that they're filling each other's gaps. During font
patching, the presence/absence of a glyph at each codepoint in the
original font takes care of the ambiguity. Since we don't have that
information, we need to hardcode which patch set "wins" for each case
(it's not always the latest set in the list). Luckily, there are only
two cases.
* Many glyphs belong to scale groups that should be scaled and aligned
as a unit. However, in `font_patcher`, the scale group is _not_ used for
_horizontal_ alignment, _unless_ the entire scale group has a single
advance width (remember, the original symbol fonts are not monospace).
This PR implements this rule by only setting `relative_width` and
`relative_x` if the group is monospace.
There are some additional tweaks to ensure that each codepoint actually
gets the rule it's supposed to when it belongs to multiple scale groups
or patch sets, and to avoid setting rules for codepoints that don't
exist in the embedded font.
Follow-up to #8563, which broke scaling without alignment. This change
recovers the behavior from before #8563, such that a scaled group is
clamped to the constraint width and height if necessary, and otherwise,
scaling does not shift the center of the group bounding box.
As a part of this change, horizontal alignment was rewritten to assume
the face is flush with the left edge of the cell. The cell-to-face
offset in the rendering code is then applied regardless of the value of
`align_horizontal`. This both simplifies the code and improves
consistency, as it ensures that the offset is the same for all
non-bitmap glyphs (rounded in FreeType, not rounded in CoreText). It's
the right thing to do following the align-to-face changes in #8563.
In CoreText, when thickening (font smoothing) is enabled or Ghostty is
synthesizing a bold face, the glyph bounding box is padded to make sure
the thicker glyph can fit. Currently, this happens before applying
constraints (scaling and alignment), which makes the size and position
of constrained glyphs dependent on font size, font thickening strength,
and display DPI.
With this PR, constraints are applied before any other adjustments, and
padding is applied directly to the rasterization canvas without
modifying any metrics.
For consistency, I also moved constraint application above emboldening
in the FreeType code, although under that API, the two operations are
orthogonal as far as I can tell.
Secondly, this PR moves glyph centering above bitmap quantization, as
centering is generally fractional and will therefore undo the quantizing
if done after.
Supersedes #8552.
In Freetype, measure rect after emboldening, so constraints apply to the
true glyph size like in CoreText.
In CoreText, don't let font smoothing affect the rect (only the canvas).
This adds a new script we can manually run that downloads all the files
that need to be uploaded to the mirror and updates our build.zig.zon.
The upload still happens manually [by me] but this simplifies the task
greatly.
This adds a new script we can manually run that downloads all the files
that need to be uploaded to the mirror and updates our build.zig.zon.
The upload still happens manually [by me] but this simplifies the task
greatly.
Replaces #8372
Before merge I'm going to squash this and give @pluiedev coauthor, since
I took a lot of her work. I just have to go through this myself to make
sure I learn all the changes in Zig 0.15, but as I got things, I copy
and pasted her work in. My work is probably less thorough and there are
places we can convert deprecated things, probably, but this results in
green CI.
## Benchmarks
It looks like there are some speed regressions in isolated places. I'm
not sure if this is noise or not, I'm going to keep running some tests.
If someone can check macOS that'd be helpful (my vtebench is down on
macOS atm), cc @qwerasd205 if interested.
On an x86_64 system:

Fixes#8991
Uses OSC 133 esc sequences to keep track of how long commands take to
execute. If the user chooses, commands that take longer than a user
specified limit will trigger a notification. The user can choose between
a bell notification or a desktop notification.
Signal handlers are connected to surface objects in two spots - when a
tab is added to a page and when the split tree changes. This resulted in
duplicate signal handlers being added for each surface. This was most
noticeable when copying the selection to the clipboard - you would see
two "Copied to clipboard" toasts. Ensure that there is only one signal
handler by removing any old ones before adding the new ones.
You can pretty simply reproduce a crash on `main` in `Debug` mode by
running `printf "مرحبًا \n"` with your primary font set to one that
supports Arabic such as Cascadia Code/Mono or Kawkab Mono, which will
cause CoreText to output the shaped glyphs non-monotonically which hits
the assert we have in the renderer.
In `ReleaseFast` this assert is skipped and because we already moved
ahead to the space glyph (which belongs at the end but is emitted first)
all of the glyphs up to that point are lost. I believe this is probably
the cause of #8280, I tested and this change seems to fix it at least.
Included in this PR is a little optimization: we were allocating buffers
to copy glyphs etc. from runs to every time, even though CoreText
provides `CTRunGet*Ptr` functions which get *pointers* to the internal
storage of these values- these aren't guaranteed to return a usable
pointer but in that case we can always fall back to allocating again.
Also avoided allocation while processing glyphs by ensuring capacity
beforehand immediately after creating the `CTLine`.
The performance impact of this PR is negligible on my machine and
actually seems to be positive, probably due to avoiding allocations if I
had to guess.