This meshes well with the sequence of instructions that we
get from harfbuzz.
This will need some vendoring to integrate with wezterm's build
on all platforms; that can come later.
Still need to hook up gradients.
We need to make a couple of passes over the paint instructions,
and making a nice interface around FontFuncs and DrawFuncs was
taking up a lot of boilerplate.
Adjust so that we accumulate parsed PaintOps and DrawOps instead.
This makes the code smaller and easier to grok.
Still has trouble rasterizing the new noto color emoji font though.
I think this fixes up the discrepancy I had in metrics with images.
The "solution" is to tell harfbuzz to scale to the selected
bitmap strike size instead of the the computed pixel size for
the current settings.
I'm experimenting with using cairo's 2D graphics for glyph related
drawing operations, and perhaps more stuff in the UI in the future.
The challenge is that no one has yet encapsulated its build in a
cargo-friendly way.
This commit is that attempt.
The strategy is this:
* `deps/cairo` is ostensibly the same thing as https://github.com/gtk-rs/gtk-rs-core/tree/master/cairo/sys
which is the cairo-sys-rs crate
* Its build.rs has been replaced with a version that builds from the C
sources that are found in-tree; it will never look for the system
cairo library
* A pair of scripts to import pixman (a required dep of cairo) and
cairo itself in a repeatable way are include, for if/when we need
to update the vendored sources
Cairo is a mature library and doesn't release very often.
* The workspace sets a patch for crates.io so that cairo-rs has
its cairo-sys-rs dep redirected to the local build.
I'm not planning to upstream this stuff to gtk-rs-core as full cairo
depends on a lot more things than are dealt with here, so it would be a
PITA to handle that generally.
This vendoring strips out things that are not used, so the cairo
library that remains:
* Is not internally thread safe; no TLS or mutex support is enabled
in either of them. That's fine because the high level cairo-rs
wrapper is not Send+Sync, which means that rust will only allow
it to be used single threaded anyway.
* Only has the basic recording and image surfaces
* No platform support for win32/xlib/xcb and so on
The vertical alignment is wonky, and some glyphs have the wrong
aspect and are missig colors. eg: the watermelon glyph in Noto Color
Emoji (U+1f349).
Turn this off by default, and skip loading fonts that have svg by
default.
The approach we were using previously was to ask macOS for the fallback
font list, but it didn't include the correct fonts for certain
codepoints.
Switch to using an alternative API that asks macOS which font to use for
a specific codepoint.
refs: #4099
- Removes closures and function calls for types that implement default:
```rust
// Change
let _my_str = get_str().unwrap_or(String::new);
// To
let _my_str = get_str().unwrap_or_default();
```
- Uses the `.cloned()/.copied()` methods where possible
- Use function pointer instead of simple closure
May improve performace, as closures generate more code, and this might
unlock some inlining opportunities.
- Use `find` instead of `position(..).next()`
- Use `any` instead of `position(..).next().is_some()/.is_none()`
- Use `first/next` instead of `get(0)/nth(0)`
- Prefer `for` loops over `while let` loops on iterators
May improve performance.
In https://github.com/wez/wezterm/issues/2932 the user desired to have
brightened text without the boldness, as they were accustomed to that
behavior in a couple of other terminal emulators.
This commit changes the `bold_brightens_ansi_colors` from a simple
boolean to a tristate that allows for not changing the brightness,
changing the brightness, and changing the brightness while adjusting
the boldness down to normal levels.
boolean values are accepted for backwards compatibility.
This commit introduces a rough first pass at a command palette modal.
It is an adaptation of the emoji character selector and needs
refinement.
Importantly, the default pane selector key assignment now calls
into this new command palette instead.
refs: https://github.com/wez/wezterm/issues/1485
Do it "more properly": use intrusive list linkage to manage three
indices:
* hash lookup
* recency
* frequency
eviction is frequency based, but in order to avoid things that were
super hot in the past and that are no longer hot clogging up the cache,
eviction will incrementally age out least recently used entries that
haven't been active in the span of some number of get/put operations.
Aging scales down the frequency value to reduce its strength, so an aged
item isn't necessarily immediately a candidate for removal, it just
makes it more likely to be picked up by the frequency based removal as
it goes unused for an extended period.
This sequence forms a grapheme with cell_width=2, but harfbuzz returns
it as two distinct clusters, causing our prior logic to shape them
independently from different fonts, but our logic for assessing width
would resolve them both to the same cell and double-count their width,
leading to issues with the rendered result.
This commit revises our clustering logic to add a pass that compares
the harfbuzz cluster positions with the cell-based positions from
the presentation_width that may have been provided. We use the starting
cell positions from that to order and de-dup so that clusters aren't
split in the wrong place.
refs: https://github.com/wez/wezterm/issues/2572
I was going to upgrade to the unicode 15 font, but in testing this I
decided that the logic is slightly complex and the glyphs are often
difficult to see at most terminal font sizes, which generates questions
from users, so just fall back to notdef.
The clustered line storage impl of get_cell() is O(column-index)
as cells have to be iterated in order.
The render pass was calling it 3 times to resolve information
about the cursor; reduce that to just once.
It was also calling it once per cell to determine whether the
cell needed to be replaced with a custom glyph if custom block
glyphs were enabled, making it accidentally quadratic!
While it wasn't especially expensive, it did show up in profiling,
so this commit removes that call: we can cache the block glyph
key in the shaper info which is a better place for it anyway,
so that's what we do.
Similarly, there was some extraneous work to call get_cell
when computing some shaper info; remove that too!
That one might be slightly contentious: the is-followed-by-space
logic used to check the successor cell by index to see if it
was a space, but now looks at the successor shaped glyph to see
if it was a space. That might actually be a better choice, but
it may have some ripple effects.
According to its benchmarks, it's almost 2x faster than
unicode_segmentation. It doesn't appear to make a visible
difference to `time cat bigfile`, but I'll take anything
that gives more headroom for such little effort of switching.
When falling back to presentation-ambivalent font lookup, restart
our shaper run from font_idx=0 rather than the current font index.
For:
```
wezterm ls-fonts --text "$(printf \\U1faf0)"
```
the current font index was the last resort font so we'd never
search over anything useful in the second pass.
Looking back at 4fc8dfb374, I can't
see a good reason for starting at the later offset.
We were getting data like this back from harfbuzz:
shaped font_idx=0 "파인더에서 만든 폴더" as: [.notdef=0+448|.notdef=0+448|.notdef=6+448|.notde=6+448|.notdef=6+448|.notdef=15+448|.notdef=15+448|.notdef=21+448|.notdef=21+448|.notdef=27+448|.notdef=27+448|space=33+448|.notdef=34+448|.notdef=34+448|.notdef=34+448|.notdef=43+448|.notdef=43+448|.notdef=43+448|space=52+448|.notdef=53+448|.notdef=53+448|.notdef=53+448|.notdef=62+448|.notdef=62+448]
which had a series of discontiguous and repeated runs for the same
cluster/region, but due to a logic error, we weren't coalescing them
together and were passing somewhat nonsensical ranges to the
next font for shaping.
This commit "simply" ensures that we code the checks for codepoint==0
(the `.nodef` seen above) and the results are at least correct
for this particular case.
refs: https://github.com/wez/wezterm/issues/2482
This commit is a result of debugging a problem with a particular font
where a VS2 variation of a glyph produced incorrect shaping.
Further investigation showed that this was specific to using freetype
font functions and that switching to opentype functions produces the
correct shaping information in that case.
Further-further investigation showed that this difference in behavior
was really due to the font file being out of spec and freetype returning
unexpected data as a result.
This commit allows switching to using harfbuzz's own opentype font+face
(rather than freetype) and/or switching the freetype-based font to using
opentype font functions. These two options don't yield equivalent
results in the wezterm integration: a couple of our shaping tests
fail due to the x-advances not being the same. Those can be drastically
different in some cases (eg: I seem to get 0 for certain bitmap strikes,
and for Roboto the value is off by a factor of about 1.5).
This is incomplete and not something I want to turn on by default at
the moment, but I don't want to lose this work, hence this commit.
refs: https://github.com/wez/wezterm/issues/2475
refs: https://github.com/harfbuzz/harfbuzz/issues/3806
We've been using hb with freetype faces. This gives us the option
of using harfbuzz's own opentype based face and function set.
It doesn't change any behavior: this is just newly available code.
refs: https://github.com/wez/wezterm/issues/2475
CTRL-SHIFT-U is a new default key assignment for this new modal.
It opens up a fuzzy searchable browser that defaults to showing
emoji/emoticons. The category can by cycled through the suggested
emoji categories using CTRL-r. Unlike the system emoji palette,
wezterm includes a category for nerdfont symbols, and another
that is a list of all unicode codepoint names, so you should be
able to browse for pretty much any codepoint you can think of.
The modal also allows fuzzy searching based on:
* The official unicode name
* The github shortcode
* codepoint value in hex
so if you know the codepoint value but not the name, you can
still find a way to input what you're looking for.
Pressing Enter will copy the selected item to the clipboard
send it to the active pane, and cancel the modal. You can therefore
repeat the insert by simply pasting.
I plan to add frecency to this in a later commit: that way the
frequently/recently used selections will show in a category of
their own and make it easier to re-input them.
refs: https://github.com/wez/wezterm/issues/2163
This avoids a confusing situation where we'd not bother to resolve
a font for a given codepoint for say bold text if we had previously
resolved it for normal text.
This hashset would be more useful if we maintained a mapping of
codepoint to font at that layer, but we don't.
The simplest thing to do for this is to allow the search to continue
and succeed.
refs: https://github.com/wez/wezterm/issues/2158
refs: https://github.com/wez/wezterm/issues/1913