From 16cad760a51497bb14202c4f61ca49e418f4f895 Mon Sep 17 00:00:00 2001
From: Gautier Cailly <109429289+gcailly@users.noreply.github.com>
Date: Mon, 6 Apr 2026 14:25:04 +0200
Subject: [PATCH] Integrate harfrust for text shaping (#8031)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Related to #56 (Improve text — tracking issue)
## Summary
This PR integrates [harfrust](https://crates.io/crates/harfrust) (a
pure-Rust port of HarfBuzz) into epaint's text layout pipeline,
replacing the character-by-character glyph positioning with proper
OpenType text shaping.
### What this enables
- **GPOS kerning**: most modern fonts only ship kerning in GPOS tables
(not the legacy `kern` table). Pairs like "AV", "VA", "AT" are now
properly tightened.
- **GSUB substitutions**: ligatures (fi, fl), contextual alternates, and
other OpenType features.
- **Combining marks**: diacritics (e.g. ɔ̃) are positioned via anchor
tables instead of being rendered as standalone replacement glyphs.
### Before/After
#### Kerning, etc.
#### Ligatures
### Architecture
The shaping integrates into the existing pipeline without changing the
public API:
1. **`Font::segment_into_runs`** — segments text into contiguous runs by
font face (grapheme-cluster aware, never splits combining sequences)
2. **`FontFace::shape_text`** — calls harfrust to shape each run,
returning glyph IDs + positioned advances/offsets
3. **`layout_shaped_run`** — emits `Glyph` structs from the shaping
output, with NOTDEF fallback to other font faces for missing glyphs
4. **Buffer recycling** — `FontsImpl` pools a `harfrust::UnicodeBuffer`
to avoid per-layout allocations
### Disclaimer
I'm far from being a good Rust programmer. Claude Code did most of the
heavy lifting here. I did my best and used my limited knowledge to avoid
making too many mistakes. If this PR isn't up to quality standards,
please don't hesitate to close it.
## Test plan
- [x] `cargo test -p epaint` — all 18 text tests pass, including 6 new
ones
- [x] `cargo clippy -p epaint --all-features` — clean
- [x] `cargo fmt` — clean
- [ ] Snapshot tests need regeneration (expected: shaping changes glyph
positions)
- New tests added:
- `test_gpos_kerning` — verifies GPOS kerning tightens "AV", "VA", "AT"
pairs
- `test_combining_diacritics` — combining tilde doesn't add extra width
- `test_shaping_basic_latin` — sanity check for Latin text
- `test_shaping_empty_string` — empty input doesn't panic
- `test_shaping_multiple_newlines` — newline splitting works correctly
- `test_shaping_mixed_font_fallback` — Latin + emoji in same string
---------
Co-authored-by: Emil Ernerfeldt
---
Cargo.lock | 62 +-
Cargo.toml | 4 +-
.../egui_demo_app/tests/snapshots/clock.png | 4 +-
.../tests/snapshots/custom3d.png | 4 +-
.../tests/snapshots/easymarkeditor.png | 4 +-
.../tests/snapshots/imageviewer.png | 4 +-
.../tests/snapshots/demos/Bézier Curve.png | 4 +-
.../tests/snapshots/demos/Clipboard Test.png | 4 +-
.../tests/snapshots/demos/Code Editor.png | 4 +-
.../tests/snapshots/demos/Code Example.png | 4 +-
.../tests/snapshots/demos/Cursor Test.png | 4 +-
.../tests/snapshots/demos/Dancing Strings.png | 4 +-
.../tests/snapshots/demos/Drag and Drop.png | 4 +-
.../tests/snapshots/demos/Extra Viewport.png | 4 +-
.../tests/snapshots/demos/Font Book.png | 4 +-
.../tests/snapshots/demos/Frame.png | 4 +-
.../tests/snapshots/demos/Grid Test.png | 4 +-
.../tests/snapshots/demos/Highlighting.png | 4 +-
.../tests/snapshots/demos/ID Test.png | 4 +-
.../snapshots/demos/Input Event History.png | 4 +-
.../tests/snapshots/demos/Input Test.png | 4 +-
.../snapshots/demos/Interactive Container.png | 4 +-
.../tests/snapshots/demos/Layout Test.png | 4 +-
.../snapshots/demos/Manual Layout Test.png | 4 +-
.../tests/snapshots/demos/Misc Demos.png | 4 +-
.../tests/snapshots/demos/Modals.png | 4 +-
.../tests/snapshots/demos/Multi Touch.png | 4 +-
.../tests/snapshots/demos/Painting.png | 4 +-
.../tests/snapshots/demos/Panels.png | 4 +-
.../tests/snapshots/demos/Popups.png | 4 +-
.../tests/snapshots/demos/SVG Test.png | 4 +-
.../tests/snapshots/demos/Scene.png | 4 +-
.../tests/snapshots/demos/Screenshot.png | 4 +-
.../tests/snapshots/demos/Scrolling.png | 4 +-
.../tests/snapshots/demos/Sliders.png | 4 +-
.../tests/snapshots/demos/Strip.png | 4 +-
.../tests/snapshots/demos/Table.png | 4 +-
.../snapshots/demos/Tessellation Test.png | 4 +-
.../tests/snapshots/demos/Text Layout.png | 4 +-
.../tests/snapshots/demos/TextEdit.png | 4 +-
.../tests/snapshots/demos/Tooltips.png | 4 +-
.../tests/snapshots/demos/Undo Redo.png | 4 +-
.../tests/snapshots/demos/Window Options.png | 4 +-
.../snapshots/demos/Window Resize Test.png | 4 +-
.../snapshots/image_kerning/image_dark_x1.png | 4 +-
.../snapshots/image_kerning/image_dark_x2.png | 4 +-
.../image_kerning/image_light_x1.png | 4 +-
.../image_kerning/image_light_x2.png | 4 +-
.../snapshots/italics/image_dark_x1.00.png | 4 +-
.../snapshots/italics/image_dark_x1.41.png | 4 +-
.../snapshots/italics/image_dark_x2.00.png | 4 +-
.../snapshots/italics/image_light_x1.00.png | 4 +-
.../snapshots/italics/image_light_x1.41.png | 4 +-
.../snapshots/italics/image_light_x2.00.png | 4 +-
.../tests/snapshots/modals_1.png | 4 +-
.../tests/snapshots/modals_2.png | 4 +-
.../tests/snapshots/modals_3.png | 4 +-
...rop_should_prevent_focusing_lower_area.png | 4 +-
.../snapshots/rendering_test/dpi_1.00.png | 4 +-
.../snapshots/rendering_test/dpi_1.25.png | 4 +-
.../snapshots/rendering_test/dpi_1.50.png | 4 +-
.../snapshots/rendering_test/dpi_1.67.png | 4 +-
.../snapshots/rendering_test/dpi_1.75.png | 4 +-
.../snapshots/rendering_test/dpi_2.00.png | 4 +-
.../tests/snapshots/tessellation_test.png | 3 -
.../tessellation_test/Additive rectangle.png | 4 +-
.../tessellation_test/Blurred stroke.png | 4 +-
.../snapshots/tessellation_test/Blurred.png | 4 +-
.../tessellation_test/Minimal rounding.png | 4 +-
.../snapshots/tessellation_test/Normal.png | 4 +-
.../Thick stroke, minimal rounding.png | 4 +-
.../tessellation_test/Thin filled.png | 4 +-
.../tessellation_test/Thin stroked.png | 4 +-
.../tests/snapshots/text_selection_0.png | 4 +-
.../tests/snapshots/text_selection_1.png | 4 +-
.../snapshots/widget_gallery_dark_x1.png | 4 +-
.../snapshots/widget_gallery_dark_x2.png | 4 +-
.../snapshots/widget_gallery_light_x1.png | 4 +-
.../snapshots/widget_gallery_light_x2.png | 4 +-
.../tests/snapshots/combobox_closed.png | 4 +-
.../tests/snapshots/combobox_opened.png | 4 +-
.../tests/snapshots/menu/closed_hovered.png | 4 +-
.../tests/snapshots/menu/opened.png | 4 +-
.../tests/snapshots/menu/submenu.png | 4 +-
.../tests/snapshots/menu/subsubmenu.png | 4 +-
.../tests/snapshots/readme_example.png | 4 +-
.../snapshots/should_wait_for_images.png | 4 +-
.../tests/snapshots/test_masking.png | 4 +-
.../tests/snapshots/test_scroll_initial.png | 4 +-
.../tests/snapshots/test_shrink.png | 4 +-
.../tests/snapshots/test_tooltip_hidden.png | 4 +-
.../tests/snapshots/test_tooltip_shown.png | 4 +-
crates/epaint/Cargo.toml | 3 +
crates/epaint/src/text/font.rs | 145 ++--
crates/epaint/src/text/fonts.rs | 14 +
crates/epaint/src/text/text_layout.rs | 665 +++++++++++++++---
.../tests/snapshots/atom_letter_spacing.png | 4 +-
.../tests/snapshots/button_shortcut.png | 4 +-
tests/egui_tests/tests/snapshots/grow_all.png | 4 +-
...orizontal_wrapped_multiline_row_height.png | 4 +-
...wrapped_multiline_row_height_reference.png | 4 +-
.../hovering_should_preserve_text_format.png | 4 +-
.../tests/snapshots/layout/atoms_image.png | 4 +-
.../tests/snapshots/layout/atoms_minimal.png | 4 +-
.../snapshots/layout/atoms_multi_grow.png | 4 +-
.../tests/snapshots/layout/button.png | 4 +-
.../tests/snapshots/layout/button_image.png | 4 +-
.../layout/button_image_shortcut.png | 4 +-
.../tests/snapshots/layout/checkbox.png | 4 +-
.../snapshots/layout/checkbox_checked.png | 4 +-
.../tests/snapshots/layout/drag_value.png | 4 +-
.../tests/snapshots/layout/radio.png | 4 +-
.../tests/snapshots/layout/radio_checked.png | 4 +-
.../snapshots/layout/selectable_value.png | 4 +-
.../layout/selectable_value_selected.png | 4 +-
.../tests/snapshots/layout/slider.png | 4 +-
.../tests/snapshots/layout/text_edit.png | 4 +-
.../tests/snapshots/layout/text_edit_clip.png | 4 +-
.../snapshots/layout/text_edit_no_clip.png | 4 +-
.../layout/text_edit_placeholder_clip.png | 4 +-
.../layout/text_edit_prefix_suffix.png | 4 +-
.../egui_tests/tests/snapshots/max_width.png | 4 +-
.../tests/snapshots/max_width_and_grow.png | 4 +-
.../tests/snapshots/rotated_ellipse.png | 4 +-
.../tests/snapshots/rotated_rect.png | 4 +-
.../tests/snapshots/shrink_first_text.png | 4 +-
.../tests/snapshots/shrink_last_text.png | 4 +-
.../tests/snapshots/sides/default_long.png | 4 +-
.../sides/default_long_fit_contents.png | 4 +-
.../snapshots/sides/shrink_left_long.png | 4 +-
.../sides/shrink_left_long_fit_contents.png | 4 +-
.../snapshots/sides/shrink_right_long.png | 4 +-
.../sides/shrink_right_long_fit_contents.png | 4 +-
.../tests/snapshots/sides/wrap_left_long.png | 4 +-
.../sides/wrap_left_long_fit_contents.png | 4 +-
.../tests/snapshots/sides/wrap_right_long.png | 4 +-
.../sides/wrap_right_long_fit_contents.png | 4 +-
.../tests/snapshots/size_max_size.png | 4 +-
.../snapshots/text_edit_delay_0_empty.png | 4 +-
.../text_edit_delay_1_h_invisible.png | 4 +-
.../tests/snapshots/text_edit_halign.png | 4 +-
.../tests/snapshots/visuals/button.png | 4 +-
.../tests/snapshots/visuals/button_image.png | 4 +-
.../visuals/button_image_shortcut.png | 4 +-
.../button_image_shortcut_selected.png | 4 +-
.../tests/snapshots/visuals/checkbox.png | 4 +-
.../snapshots/visuals/checkbox_checked.png | 4 +-
.../tests/snapshots/visuals/drag_value.png | 4 +-
.../tests/snapshots/visuals/radio.png | 4 +-
.../tests/snapshots/visuals/radio_checked.png | 4 +-
.../snapshots/visuals/selectable_value.png | 4 +-
.../visuals/selectable_value_selected.png | 4 +-
.../tests/snapshots/visuals/slider.png | 4 +-
.../tests/snapshots/visuals/text_edit.png | 4 +-
.../snapshots/visuals/text_edit_clip.png | 4 +-
.../snapshots/visuals/text_edit_no_clip.png | 4 +-
.../visuals/text_edit_placeholder_clip.png | 4 +-
.../visuals/text_edit_prefix_suffix.png | 4 +-
158 files changed, 998 insertions(+), 502 deletions(-)
delete mode 100644 crates/egui_demo_lib/tests/snapshots/tessellation_test.png
diff --git a/Cargo.lock b/Cargo.lock
index 5814d9a85..58817670a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1540,6 +1540,7 @@ dependencies = [
"emath",
"epaint_default_fonts",
"font-types",
+ "harfrust",
"log",
"mimalloc",
"nohash-hasher",
@@ -1551,6 +1552,8 @@ dependencies = [
"similar-asserts",
"skrifa",
"smallvec",
+ "unicode-general-category",
+ "unicode-segmentation",
"vello_cpu",
]
@@ -1658,12 +1661,9 @@ dependencies = [
[[package]]
name = "fearless_simd"
-version = "0.3.0"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fb2907d1f08b2b316b9223ced5b0e89d87028ba8deae9764741dba8ff7f3903"
-dependencies = [
- "bytemuck",
-]
+checksum = "76258897e51fd156ee03b6246ea53f3e0eb395d0b327e9961c4fc4c8b2fa151a"
[[package]]
name = "file_dialog"
@@ -2018,6 +2018,15 @@ dependencies = [
"bitflags 2.9.4",
]
+[[package]]
+name = "guillotiere"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b17e70c989c36bad147b27a58d148c0741c51448aa5653436547323e524d0ab"
+dependencies = [
+ "euclid",
+]
+
[[package]]
name = "half"
version = "2.6.0"
@@ -2029,6 +2038,19 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "harfrust"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9da2e5ae821f6e96664977bf974d6d6a2d6682f9ccee23e62ec1d134246845f9"
+dependencies = [
+ "bitflags 2.9.4",
+ "bytemuck",
+ "core_maths",
+ "read-fonts",
+ "smallvec",
+]
+
[[package]]
name = "hashbrown"
version = "0.15.2"
@@ -3732,6 +3754,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b634fabf032fab15307ffd272149b622260f55974d9fad689292a5d33df02e5"
dependencies = [
"bytemuck",
+ "core_maths",
"font-types",
]
@@ -4732,6 +4755,12 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e"
+[[package]]
+name = "unicode-general-category"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b993bddc193ae5bd0d623b49ec06ac3e9312875fdae725a975c51db1cc1677f"
+
[[package]]
name = "unicode-ident"
version = "1.0.24"
@@ -4899,28 +4928,41 @@ dependencies = [
]
[[package]]
-name = "vello_common"
-version = "0.0.6"
+name = "vello_api"
+version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bd1a4c633ce09e7d713df1a6e036644a125e15e0c169cfb5180ddf5836ca04b"
+checksum = "a5088cd0113bc5332c753f24503825e3bc93e26c7883c9dc3ad9637bb62c4634"
+dependencies = [
+ "bytemuck",
+ "peniko",
+]
+
+[[package]]
+name = "vello_common"
+version = "0.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "986dc49a501a683477614bf07b8e7b6c79ae4828efce3bf22e51850f4a0a8a4c"
dependencies = [
"bytemuck",
"fearless_simd",
+ "guillotiere",
"hashbrown 0.16.1",
"log",
"peniko",
"skrifa",
"smallvec",
+ "thiserror 2.0.18",
]
[[package]]
name = "vello_cpu"
-version = "0.0.6"
+version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0162bfe48aabf6a9fdcd401b628c7d9f260c2cbabb343c70a65feba6f7849edc"
+checksum = "a678f91c7524a3a9ac9a19df9f83552866ec70b2ca26441b916a6b219b6aa2de"
dependencies = [
"bytemuck",
"hashbrown 0.16.1",
+ "vello_api",
"vello_common",
]
diff --git a/Cargo.toml b/Cargo.toml
index d589ef954..2f5d5cf50 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -93,6 +93,7 @@ font-types = { version = "0.11.0", default-features = false, features = ["std"]
glow = "0.17.0"
glutin = { version = "0.32.3", default-features = false }
glutin-winit = { version = "0.5.0", default-features = false }
+harfrust = "0.5.2"
home = "0.5.9"
image = { version = "0.25.6", default-features = false }
jiff = { version = "0.2.23", default-features = false }
@@ -136,8 +137,9 @@ tokio = "1.49"
toml = {version = "1.0.0", default-features = false }
type-map = "0.5.1"
unicode_names2 = { version = "2.0.0", default-features = false }
+unicode-general-category = "1.1.0"
unicode-segmentation = "1.12.0"
-vello_cpu = { version = "0.0.6", default-features = false, features = ["std", "u8_pipeline", "f32_pipeline"] }
+vello_cpu = { version = "0.0.7", default-features = false, features = ["std", "u8_pipeline", "f32_pipeline"] }
wasm-bindgen = "0.2.108" # Keep wasm-bindgen version in sync in: setup_web.sh, Cargo.toml, Cargo.lock, rust.yml. Don't update this spuriously, because of https://github.com/rerun-io/rerun/issues/8766
wasm-bindgen-futures = "0.4.58"
wayland-cursor = { version = "0.31.11", default-features = false }
diff --git a/crates/egui_demo_app/tests/snapshots/clock.png b/crates/egui_demo_app/tests/snapshots/clock.png
index 0c5228a26..347bdd568 100644
--- a/crates/egui_demo_app/tests/snapshots/clock.png
+++ b/crates/egui_demo_app/tests/snapshots/clock.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:63021012cccfca02d09aa424333453140ae4da3ae58fa32b422f6152ba25741c
-size 335394
+oid sha256:288e11a1fa684575155826a760d5aecc5855e1f4b68bc8954441bf3ac015ee84
+size 335175
diff --git a/crates/egui_demo_app/tests/snapshots/custom3d.png b/crates/egui_demo_app/tests/snapshots/custom3d.png
index e14066758..6778d8b92 100644
--- a/crates/egui_demo_app/tests/snapshots/custom3d.png
+++ b/crates/egui_demo_app/tests/snapshots/custom3d.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4470063fe210d2e5170d6609c2603fff1984b8ee76fb65a1f60a1c4cfdf46ce8
-size 92796
+oid sha256:d674918c635bfc865043f2123c0f5d4a671dd21ba7b878c056e817b19f2e8f00
+size 92770
diff --git a/crates/egui_demo_app/tests/snapshots/easymarkeditor.png b/crates/egui_demo_app/tests/snapshots/easymarkeditor.png
index 5118065c4..f8237d940 100644
--- a/crates/egui_demo_app/tests/snapshots/easymarkeditor.png
+++ b/crates/egui_demo_app/tests/snapshots/easymarkeditor.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:84f0e72ce337d56f3767ebed1ab6a47f3d27c9fbcce4d8a19aeab358e12920f5
-size 169664
+oid sha256:fa67354cfe4d9cb8774c8de614be5975853a4a817ceaf96c3ec7a968de638d8d
+size 169740
diff --git a/crates/egui_demo_app/tests/snapshots/imageviewer.png b/crates/egui_demo_app/tests/snapshots/imageviewer.png
index ae238b029..c47f260e9 100644
--- a/crates/egui_demo_app/tests/snapshots/imageviewer.png
+++ b/crates/egui_demo_app/tests/snapshots/imageviewer.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6030f2f3da3dbbdf8bf3eaf429f222acffb624c7696b654d8b6e64273d49be58
-size 99008
+oid sha256:b9f5204a9b8f15e0f144e66f0df8685e4e3ed90cd265474f2600fdd4cb5df390
+size 98934
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Bézier Curve.png b/crates/egui_demo_lib/tests/snapshots/demos/Bézier Curve.png
index 71bed3294..96d7706ee 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Bézier Curve.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Bézier Curve.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bff16d453b960bb9abcdd9f72dab73f8f25da6339a0e1c310ed352f57080db93
-size 32426
+oid sha256:10d64e017d1d0eba736a4471d28b1602a0cb69d8e2ab53f4ee604b01c9343116
+size 32475
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Clipboard Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Clipboard Test.png
index f987b948d..c9a05a629 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Clipboard Test.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Clipboard Test.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:24f4a9745c60c0353ece5f8fc48200671dcb185f4f0b964bbe66bf4a2fe71d7a
-size 27067
+oid sha256:ab0d730ce0cf5f1d79947601def4f60c0a015e23a5dcd780df65c7ddc7ae7156
+size 27194
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Code Editor.png b/crates/egui_demo_lib/tests/snapshots/demos/Code Editor.png
index f4b7690fc..6134dfad9 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Code Editor.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Code Editor.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:75a9cd9a3315b236c23a53e890de1a821d39c3327813d06df85ba86d2ed50cc7
-size 26887
+oid sha256:6fccbda741a056ae30a7bfd7497f7b0adfb337bdb885d247fbdfef43cc24b54c
+size 26948
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Code Example.png b/crates/egui_demo_lib/tests/snapshots/demos/Code Example.png
index 8c6077a1c..d43e856aa 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Code Example.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Code Example.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b849adf0ff9a06e1f7bfa22ef32b13224c7e62429cf675286110729156434d12
-size 76531
+oid sha256:26d247655398bae33c724ad3c3bdcab330d194093b07442708d5069e256f636b
+size 76542
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Cursor Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Cursor Test.png
index d4c9508f9..60d3993ef 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Cursor Test.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Cursor Test.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d4e33c7f817100d8414bba245ee7886354b86109f383d59e87a197e39501f0a0
-size 62604
+oid sha256:e3389491f9f5c54cfc2e295abe76ad53f223c31e9489e1d07a8323cf14fcf37d
+size 62628
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Dancing Strings.png b/crates/egui_demo_lib/tests/snapshots/demos/Dancing Strings.png
index 40153611c..c59717683 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Dancing Strings.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Dancing Strings.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:93fcc271831167cb077f3de0a9f0e27037f9e5a2ce94e056bd6f1ede9890cb7e
-size 27818
+oid sha256:6e42e801758bb9e6130a4e94bd0857d6f254e68a7dedebec5af5cb7f7d896068
+size 27822
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Drag and Drop.png b/crates/egui_demo_lib/tests/snapshots/demos/Drag and Drop.png
index 049d585ec..f3c65337f 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Drag and Drop.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Drag and Drop.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d194db1705b36c1ee6189878a323a591555493c9319b7c2ddfc0cb0541055aca
-size 20948
+oid sha256:41e68fd3a679e2a6e3dd81129de5aa1ded3a8f24cc7b1f2ba0b876240d309d9b
+size 21019
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Extra Viewport.png b/crates/egui_demo_lib/tests/snapshots/demos/Extra Viewport.png
index 1440d2be2..6a050e0e8 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Extra Viewport.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Extra Viewport.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:62af1b6d248b731b0930c51e481118ae01a5d8c08f27697ff121a47fefea83bf
-size 10795
+oid sha256:3db502ec416b322e0f98e9737faa52d5d2fd308d47649710fffa0b0bc5996f52
+size 10783
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Font Book.png b/crates/egui_demo_lib/tests/snapshots/demos/Font Book.png
index ac85845f9..b187b4cfd 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Font Book.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Font Book.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:deff441cd1d9142352f8759dff4b759f4572f0ddf93752349314da77abe4b254
-size 115028
+oid sha256:c39ae3420fe01d696a032d8d052c405c5623a9208fc673f5cf09188b1e6a539b
+size 115447
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Frame.png b/crates/egui_demo_lib/tests/snapshots/demos/Frame.png
index b8791ed2e..658cb0922 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Frame.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Frame.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:20ea4f93ee50c7a3585aef74c66d7700083ac1c16519b0704b70387849d9d2bc
-size 25057
+oid sha256:19322248e8335301b2ce31fc1f1352993a374dda945d227784fecea2ee831761
+size 25088
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Grid Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Grid Test.png
index b8f0440b6..f6f9a3cda 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Grid Test.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Grid Test.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1b72a4c0e6d441190a7a156b8bba709e81b6c1fe7b0eacedc1ee7a3bfcf881f6
-size 99297
+oid sha256:98f8865d866a6f28ae3e3a16c815770ed691a031b1d06f7d3662a7e94f564606
+size 99318
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Highlighting.png b/crates/egui_demo_lib/tests/snapshots/demos/Highlighting.png
index a965901d5..ab7de6c2d 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Highlighting.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Highlighting.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:08c40934d4bd2a239bdcc1928d1e5eba56bac03fdded2c85cf47b020d669f07e
-size 18281
+oid sha256:39208c3c2c95f68fb37880b011f866bedd8dbccee33d163a725cb2a5cc6bb1b3
+size 18290
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/ID Test.png b/crates/egui_demo_lib/tests/snapshots/demos/ID Test.png
index abd7c485b..b899d7356 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/ID Test.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/ID Test.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:82878e4150e38fdc4b2e78203c8c661c2d9e716ab32595c298392faf6ba96105
-size 113803
+oid sha256:d251ffd6c34e4ffa7b5de7fe5ae57a2d8f48ba7c2e03711da2c3f1a3fd84648c
+size 113998
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Input Event History.png b/crates/egui_demo_lib/tests/snapshots/demos/Input Event History.png
index 46a949571..5b3a63aeb 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Input Event History.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Input Event History.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:72d49d9a35e16e7413158ba14ce9cab762925f5f5e52fbbe16292de499a177f1
-size 25791
+oid sha256:4d959e17ee5c8a32534ab98b6f08db884b2fbf25476d8dc2dc90edc79bd87ea4
+size 25821
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Input Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Input Test.png
index 8c3634222..85c205be0 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Input Test.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Input Test.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bb7e3887cf12bd00ea09b297ac361562a961f64c15b28360bc87f72f270a4065
-size 51649
+oid sha256:c923f523cc77d678929f294b360f60b9f546ddec66d5317ad0eb44bd61a5f927
+size 51733
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Interactive Container.png b/crates/egui_demo_lib/tests/snapshots/demos/Interactive Container.png
index d01e4bb7b..b7d365f3a 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Interactive Container.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Interactive Container.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:58cd3aba4392332a45f57c7dd90a9b5da386cb396c0c6319e7a7dae71e03ff30
-size 22563
+oid sha256:c9c98d7bfa08e22e217dd9e7031cc49e4b4486f1a9fdd223bd122be07af72365
+size 22550
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Layout Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Layout Test.png
index 0f50709d3..a4a82635b 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Layout Test.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Layout Test.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:26ffcf6b71108b82ce15d4cf3f9dd0ce9fe0b9563f02725fef1b74f40e749439
-size 47281
+oid sha256:68afa93605427e12fe527f3ca9613095664b4983f1f585a60f14bc2370c0a1f2
+size 47224
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Manual Layout Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Manual Layout Test.png
index 1ba4655fd..b0cb0c27b 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Manual Layout Test.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Manual Layout Test.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:faedf9631149e231d510165215c24fccec50502d58000d5f893aa047a637a68f
-size 23148
+oid sha256:33959851f1bd2386fcca8fb5700133d14d90db5a8f783fbfaa9f3aebb7b0d5b2
+size 23119
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Misc Demos.png b/crates/egui_demo_lib/tests/snapshots/demos/Misc Demos.png
index f34ac0cd4..28e6d1845 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Misc Demos.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Misc Demos.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b6b4c2e55c02fa4caf5f9f8bd2d8c0311cc4cbcf1fc2f568fe112e8e6125c675
-size 65308
+oid sha256:7b918565d66594fe53ed62bb14e357d3489335f3d037ccb088f198d944eb367d
+size 65307
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Modals.png b/crates/egui_demo_lib/tests/snapshots/demos/Modals.png
index 28fe7b683..7f0357df1 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Modals.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Modals.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3a65927cd8bd8d24e3ffbea8eb421eb22849b27dc77d36f8acd82bf5d5e63959
-size 33469
+oid sha256:f8c3c2912a3a11892e65f94792c77c79400a81d8c913109d39e8ce12f5b095c6
+size 33503
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Multi Touch.png b/crates/egui_demo_lib/tests/snapshots/demos/Multi Touch.png
index 4e2c0a458..59609d76a 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Multi Touch.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Multi Touch.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:115398e2b4b459afc2f1c49c4e60ef3f63e562650f05581372002c93030da632
-size 38374
+oid sha256:0c2c7b0d4913b59ef932f6d6349ddab5cc8619b2e8e9a8b5eb3e055a62e6ed60
+size 38382
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Painting.png b/crates/egui_demo_lib/tests/snapshots/demos/Painting.png
index da06d85bf..4d4b5c355 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Painting.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Painting.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9c595ee9b7ada33780178a6a35e26a98055a707f2ff99f6bb36e8db4ed819791
-size 18242
+oid sha256:9567f56f2dd030608798347e1ab755d95730ba5c5dd1721f1c61147be7216e87
+size 18304
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Panels.png b/crates/egui_demo_lib/tests/snapshots/demos/Panels.png
index 70e7ce90e..553f8aa0b 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Panels.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Panels.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a46457b23b7b32694564d03b42bccac2f017a756225bc54b508bb6fe2ad8ee7b
-size 249548
+oid sha256:d19d694e6a70ab6acb45668b391751e82f7beab19f9918e23821c667e8cc9cdb
+size 249733
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Popups.png b/crates/egui_demo_lib/tests/snapshots/demos/Popups.png
index 0aab4baf8..6a18dc9e5 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Popups.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Popups.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c218115d305dfa6c9ab883ac6f3a21584b4840b3ba273ea765c8a8381d78935f
-size 57181
+oid sha256:9e1c73e28020371429b3e03d540f72dbf886fd40f0ba08bb194e868bbb3c95ff
+size 57230
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/SVG Test.png b/crates/egui_demo_lib/tests/snapshots/demos/SVG Test.png
index 4b560e20a..92d19c470 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/SVG Test.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/SVG Test.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fadea24444c402695db6cbc9e03aef8a0ed3c5db487a324fb255d38c14f73dce
-size 19804
+oid sha256:c2facd3881e6b107a0dcce9d6e00008a3c9b0f31ad270c35357a87e487180f56
+size 19814
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Scene.png b/crates/egui_demo_lib/tests/snapshots/demos/Scene.png
index 2d57b2074..de52524ac 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Scene.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Scene.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f6105c95470d1342f9003ab03e71243b5e18a6f225261aee94b15f8f0501572c
-size 33542
+oid sha256:0ad81eb762150360368a97858ef30bb0d5aff72e71743fa40c3fd4d70ec84cdc
+size 33400
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Screenshot.png b/crates/egui_demo_lib/tests/snapshots/demos/Screenshot.png
index 5517e03ef..14603f2f2 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Screenshot.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Screenshot.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f2ce9062c5d1f0b0861d5df49ae64e56ba0e6501e8bd3f8a92c53aea748be78b
-size 23629
+oid sha256:c22130891755ac095d73e0494f11ee8e89d0fd0c31a321d3afb969648ece11ef
+size 23675
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Scrolling.png b/crates/egui_demo_lib/tests/snapshots/demos/Scrolling.png
index 0924d3aa9..525f23435 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Scrolling.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Scrolling.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:927a497e8b6f9ce3b71dcb67086f477e19d327c163b2b8ad868af10009c2faf2
-size 172981
+oid sha256:465f33e53ebe15b776e2d6d0710f13f2453f00bab1f6ef4319b3491f1d1d3a26
+size 173487
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Sliders.png b/crates/egui_demo_lib/tests/snapshots/demos/Sliders.png
index 28864a446..34ec70a65 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Sliders.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Sliders.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6ffba8bb50b42e47f855f62682f6d5ec10bf67b01d3aa2e843f6bf787f150d0d
-size 118562
+oid sha256:001f7a1310ddf37be4d9a7f56a95a3079f713b741824a348544561bb16c291fa
+size 118614
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Strip.png b/crates/egui_demo_lib/tests/snapshots/demos/Strip.png
index c28cac211..b9dea21f0 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Strip.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Strip.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9d8d87e4cb944def0dc28e3515243a8c1b07b9b0f88e802924d4381c1cda74db
-size 26763
+oid sha256:8105f7c2b519716cc0a45dffd5f08980f53f35c6c6b788592e1d82506cdacccc
+size 26665
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Table.png b/crates/egui_demo_lib/tests/snapshots/demos/Table.png
index 727c01434..909b766b9 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Table.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Table.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:db4c0cf1c4cdae3d416afce5c58efd1cc382be86431e547fa66bcc95a0a17ddb
-size 76364
+oid sha256:a9e83d5e83e3003830f7f719b02dd93273733a9b72d388aa42083387d02c1a20
+size 76310
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Tessellation Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Tessellation Test.png
index c1b6f506a..b1ed6bcde 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Tessellation Test.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Tessellation Test.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:57bf5220ae8f47485a07e9117abaaad36924d8c6c0f9e278cb05c455f342bff6
-size 70250
+oid sha256:3d46c87417c49c8462fac6c488e46b1482bbc75f70fe8f7af8391f0d5d28dac3
+size 70271
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Text Layout.png b/crates/egui_demo_lib/tests/snapshots/demos/Text Layout.png
index e9b302746..61065db1d 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Text Layout.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Text Layout.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7c964d07a39ad286a562b53cdfe514d568d91955e6c1ca06a0cb5e45dbe3977e
-size 60947
+oid sha256:4c47faa75a002577220a92efceab5c0ccee1ddaa17c2d2f3d6d1429dbf8fe718
+size 60887
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/TextEdit.png b/crates/egui_demo_lib/tests/snapshots/demos/TextEdit.png
index 6b1a9946b..81b49688b 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/TextEdit.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/TextEdit.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f5e9d645e1decf7624bc8f031b5e28213e64fc5f568dd3eeb1768a57fcb988c3
-size 21814
+oid sha256:9c09529c3a1c26c8f28c00fc15cc5f495842862276870c24b5ee0713954f97fc
+size 21916
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Tooltips.png b/crates/egui_demo_lib/tests/snapshots/demos/Tooltips.png
index e7ed07b04..bea2050ab 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Tooltips.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Tooltips.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:57018beba5e4fb4f1e6de9c58bf898560b3a7669159d5bad91a4e2382ef57ce0
-size 64004
+oid sha256:9d69b9a12e777ee559a481aec012935a5bfb2ca8b0d48725ecd33e7f0880b2b8
+size 64273
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Undo Redo.png b/crates/egui_demo_lib/tests/snapshots/demos/Undo Redo.png
index 92992cd83..728dc59b6 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Undo Redo.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Undo Redo.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:99fa5a5cb10c7d277eafb258af6019eda24a3c96075a50db321f52a521dede92
-size 13700
+oid sha256:f6c020860fe9cb7503cea548afbf298ebb9dc620133870b528fe7508d04150c8
+size 13691
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Window Options.png b/crates/egui_demo_lib/tests/snapshots/demos/Window Options.png
index cdc1a43dd..951a6fd41 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Window Options.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Window Options.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1cc61413bcce62cc8e0a55460a974bb56ac40936cd2e5512c4a0e0c521eaaae4
-size 35874
+oid sha256:d033935ca18ebee7e3c35629233cc3e3a73766ac8c0627fcdd8a12660eed703c
+size 35873
diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Window Resize Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Window Resize Test.png
index c769f61bd..933343f25 100644
--- a/crates/egui_demo_lib/tests/snapshots/demos/Window Resize Test.png
+++ b/crates/egui_demo_lib/tests/snapshots/demos/Window Resize Test.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:999f9cc006302b8951d97b510a02f1209969c376ecc7909ed5d7b46da27c0637
-size 483753
+oid sha256:77c9058b036770a644f1bfcf9ed1ba7a29a7c98107b1823474c55ccc2880e9e7
+size 485880
diff --git a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x1.png b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x1.png
index e48dfae92..218a4e258 100644
--- a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x1.png
+++ b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x1.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9c2990a81dfa8832f0cb1c4c0ce2f86e468a7a6f693e09efffa131ed3259e2e8
-size 15428
+oid sha256:2ef07080ca2aa10e128c646479b8b322a092d63f15b35c52ed59015e7c2a0f60
+size 15434
diff --git a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x2.png b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x2.png
index 3f9da5333..8da2d19a9 100644
--- a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x2.png
+++ b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x2.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:07d987ff87c9f41ec71ceea0caff25795bf4dff525ef4ef241d0ba786acee3e1
-size 35960
+oid sha256:4edb61c6619d5e44892fa29da0aa0a624306ae637dbbaa057e3fa47c14dc06bd
+size 35988
diff --git a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x1.png b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x1.png
index 84b808a83..1085f9969 100644
--- a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x1.png
+++ b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x1.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f5c5ce0d46231d90ccb04e158947d793d99cd5cce911c72b960b6d04feba2134
-size 16122
+oid sha256:f8da0c2e37497968864a91fa6bef7c545c37791f4f9b788ea9a2f43dd4ac16b1
+size 16116
diff --git a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x2.png b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x2.png
index ff848168a..d89daa1c0 100644
--- a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x2.png
+++ b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x2.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:60dcd590b1d00361278b135ce9ef084c7382875c71c72b19fb6e23dba68f7902
-size 39279
+oid sha256:2a603fcb2eb97943d6be3239b91cacee093adcb55a6dd14af93a72fc8b3a61fa
+size 39270
diff --git a/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.00.png b/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.00.png
index 5018d53c8..081f36a0e 100644
--- a/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.00.png
+++ b/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.00.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7389e319d9153af313cc113d97b57d462da00feb0d5f99da211552af3ac7e18a
-size 6704
+oid sha256:19c9ae55906e0ad18a9507898884ec31ef785c498fb8d10267ee848bd3f17186
+size 6705
diff --git a/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.41.png b/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.41.png
index 3a1b72bb3..0bd058217 100644
--- a/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.41.png
+++ b/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.41.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d4480dd34ed36c6bdbc2084843dd136448b3934c22b3df3e40314ba6324b5b39
-size 10306
+oid sha256:6f13116cb76e52620221b41c8dbd37b74a0da513402cbb2cb7e70c89027f5e31
+size 10313
diff --git a/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x2.00.png b/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x2.00.png
index 0f18eb109..330ecd636 100644
--- a/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x2.00.png
+++ b/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x2.00.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:624bfa884431c35cc5d852b96653f13da17e60f8545471f9fb1c3bb85b40ffc8
-size 16555
+oid sha256:6869b180f2d1dcfd9fcbb215ed3febfbe548f30035560272a4e11e465f20c592
+size 16567
diff --git a/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.00.png b/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.00.png
index 6ebc6addc..86374449e 100644
--- a/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.00.png
+++ b/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.00.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bf665389ef43524e097a7ae4eec0aa01bb788bdbb306144f20f9133f74a64b2c
-size 6941
+oid sha256:132f060b2e20b4cc0c55062367381f47856a5cc10310b903dbddc3790f475581
+size 6942
diff --git a/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.41.png b/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.41.png
index 54fdc064b..30b722245 100644
--- a/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.41.png
+++ b/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.41.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a2480d0f49a929993de70612572b321457b2507c149a25112064cfc27840e6ee
-size 11005
+oid sha256:e5ec63c5e2f5bb5c0048ee67df5b821a30f89ba35dbedf72e7bc91e04a5f8359
+size 11007
diff --git a/crates/egui_demo_lib/tests/snapshots/italics/image_light_x2.00.png b/crates/egui_demo_lib/tests/snapshots/italics/image_light_x2.00.png
index 138fd8c83..ca90da21d 100644
--- a/crates/egui_demo_lib/tests/snapshots/italics/image_light_x2.00.png
+++ b/crates/egui_demo_lib/tests/snapshots/italics/image_light_x2.00.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1e0013b499934f47370a3a20b3d3a19f8a8c6db360752a35a3fb1d676d122263
-size 18068
+oid sha256:491bb98b22cf56e50d3ed10a10649db15aaffb93d7e045dfecfa26e98f537c35
+size 18070
diff --git a/crates/egui_demo_lib/tests/snapshots/modals_1.png b/crates/egui_demo_lib/tests/snapshots/modals_1.png
index 96d31e11d..d1abde4fa 100644
--- a/crates/egui_demo_lib/tests/snapshots/modals_1.png
+++ b/crates/egui_demo_lib/tests/snapshots/modals_1.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:941582e2e20a9459db1f2cb7f07fa1930acfdb12cbbe7f96f9aafbeabf8b37f6
-size 47076
+oid sha256:8bd53b56322123940496700cbd2a73e336fd80eaf49dcb19a958888d66570ddb
+size 47159
diff --git a/crates/egui_demo_lib/tests/snapshots/modals_2.png b/crates/egui_demo_lib/tests/snapshots/modals_2.png
index 3c0a88ee0..8f6976ea5 100644
--- a/crates/egui_demo_lib/tests/snapshots/modals_2.png
+++ b/crates/egui_demo_lib/tests/snapshots/modals_2.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2735a021f171f5c95888cda76e8668e1e023588c8c6c7cd382c03d8e31988fe3
-size 48209
+oid sha256:d15954e6183558141e05e1b566ec4a794d372503baf436da2a8c8c67299056f1
+size 48238
diff --git a/crates/egui_demo_lib/tests/snapshots/modals_3.png b/crates/egui_demo_lib/tests/snapshots/modals_3.png
index 28221255f..ab4a99a12 100644
--- a/crates/egui_demo_lib/tests/snapshots/modals_3.png
+++ b/crates/egui_demo_lib/tests/snapshots/modals_3.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:867bef6b55b73d127306a461e115b6f0047d582904999de80aeabae00e60c967
-size 44295
+oid sha256:1738ecf660979888c70b1046dd759fe0b082e4958814fb19077c4fed2fb4bdef
+size 44338
diff --git a/crates/egui_demo_lib/tests/snapshots/modals_backdrop_should_prevent_focusing_lower_area.png b/crates/egui_demo_lib/tests/snapshots/modals_backdrop_should_prevent_focusing_lower_area.png
index bb1935741..cbac0d342 100644
--- a/crates/egui_demo_lib/tests/snapshots/modals_backdrop_should_prevent_focusing_lower_area.png
+++ b/crates/egui_demo_lib/tests/snapshots/modals_backdrop_should_prevent_focusing_lower_area.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:936ec8b223ae7f0f32c640c127e1b6b14033bb7d168a4d1f0e6b3bd08a761e36
-size 44055
+oid sha256:dae7239dc065068147387eb313afdbaa3f0df8b81d060dbbc29f5a6a31ad76c8
+size 44309
diff --git a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.00.png b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.00.png
index b48827b6a..ea32cd32f 100644
--- a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.00.png
+++ b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.00.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fba7387f5deba5e144e2106154b15ab956a50a418857bd34e16b306d7f1a29e4
-size 588252
+oid sha256:ce6e44aeb60b6cc2179e14c467edc2d570ea1adbce08511650fc733e39f7757c
+size 590679
diff --git a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.25.png b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.25.png
index d1286d6a1..1bff62c8d 100644
--- a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.25.png
+++ b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.25.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4656f3255d7859c07b269ff655eafe21bdddb949a07aa91477b826f6e2af8c28
-size 740616
+oid sha256:2edd6679d434df3407048472aaa95e410158f28e9a13c9bd88e3f8be95b08d9d
+size 745771
diff --git a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.50.png b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.50.png
index f1892bf26..39c2a6b36 100644
--- a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.50.png
+++ b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.50.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b18ff644ba5bd0c7f094bf8eac079d8a72bc6918638b1b110002f2f0a7a362cc
-size 967860
+oid sha256:20cb796b59113853345c98e5238021a9c5c977c25689ee9201fdec1e4d98123d
+size 973781
diff --git a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.67.png b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.67.png
index c32762306..fb0da4a80 100644
--- a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.67.png
+++ b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.67.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:134caff5b8a4969055c32e8f51ca9c6eae1528b84d348691d860913e839de0d9
-size 1076746
+oid sha256:9658cc6b4dd2dd33356facc6b48cf69f9a86f976ac2dd4f16e362a2fd3f73827
+size 1081864
diff --git a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.75.png b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.75.png
index d021a1e71..736c3dd67 100644
--- a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.75.png
+++ b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.75.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d731b4ce039315e096113f3c83168165020949e57564e641e778728e35901169
-size 1125286
+oid sha256:b5d5941c8fa0456f8a92fce4888e7a2888945f5df7cfed867ef073c439c7ad9f
+size 1131030
diff --git a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_2.00.png b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_2.00.png
index 03d4fb69a..b4bf73cb7 100644
--- a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_2.00.png
+++ b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_2.00.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cfac3518220555984d47c9fdfea2202a37102250aefcc2509794f337b3a7baae
-size 1361407
+oid sha256:78ef6dba3dcf5e26a9289ce226165224c712c22f9b5dfe699b599c7d2531133b
+size 1363589
diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test.png
deleted file mode 100644
index 7c65aef2c..000000000
--- a/crates/egui_demo_lib/tests/snapshots/tessellation_test.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:aa7d25b097911f6b18308bab56d302e3dae9f8f9916f563d5703632a26eda260
-size 72501
diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Additive rectangle.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Additive rectangle.png
index 1d3f1785e..09763f516 100644
--- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Additive rectangle.png
+++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Additive rectangle.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cf21fe763e9762bca1b0f486e29a6024efcbc106a7f1ac195104acd0621cf8db
-size 45107
+oid sha256:9c0bf76e2a4d60fd4ba302b2217beaa4b0627614ff7d23294c7f5e6b81a028c7
+size 45061
diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred stroke.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred stroke.png
index 646eaa1e0..7254be665 100644
--- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred stroke.png
+++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred stroke.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2f09338e652b965cc9ae7bbb261845cd9c15d79f3d15f3c5b5326ef6d163b606
-size 86885
+oid sha256:de7db1296bdd127dfd827c6d1cc1a5a840391c3abb558be07faeb7e6612ed6e8
+size 86830
diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred.png
index e667fc387..85a4fa0da 100644
--- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred.png
+++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e298244953653e46875053b12b4fe06ee692cb58fc131233ac4172677f0f8b44
-size 118961
+oid sha256:645519e1e4c196b985b6b422ddf1ba51e7e92d1b0c80972318dcf44dab3022d3
+size 118907
diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Minimal rounding.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Minimal rounding.png
index 843c3ba3b..a3c23b831 100644
--- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Minimal rounding.png
+++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Minimal rounding.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6b9b36acf821cca71f97a3c8468fb925561f3bc2030742aef1e3c1d9e69ccc6f
-size 51419
+oid sha256:465a3aa235ea69bce6650cf6e100ffc719bba67baa0cb13d7015a0fc54d53d9a
+size 51376
diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Normal.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Normal.png
index e738e22eb..ec1182d15 100644
--- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Normal.png
+++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Normal.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f5ad7a37546d48fc5426c32534a1c452fd0bf8280346dbe6e67ac26f17f3ba8a
-size 54626
+oid sha256:aac429243686d35096760eb1b7c6a2bcad1c1d00a3341a858a6c71aaff2cf128
+size 54582
diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thick stroke, minimal rounding.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thick stroke, minimal rounding.png
index d46e593ba..fa5ea442d 100644
--- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thick stroke, minimal rounding.png
+++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thick stroke, minimal rounding.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c0b61e9d1c2bcbf891a7acd4f3c1d2bd7524133d8165e7e7984998670de5a085
-size 55090
+oid sha256:8afb610d9e86b324db22849457eb23419c4f3c240e5ee951a13ce8901003bca8
+size 55053
diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin filled.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin filled.png
index 31a1dd365..ec2750465 100644
--- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin filled.png
+++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin filled.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a2e4975e9328a6d72f2c932daddfbb00cebdb2249aceb53f667d4060a1c0ea8a
-size 36006
+oid sha256:8e1a958b753fee4bec405a74dd7727e5c477c946484ed086c5c4ffee058dd5e8
+size 35960
diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin stroked.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin stroked.png
index db20010e0..b725ec08f 100644
--- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin stroked.png
+++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin stroked.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ac6f9adeef92be9f69cb288ccafda8d522b8c3cde64352cd5369ae63668240c0
-size 35973
+oid sha256:1887d632d0994efec3dd7cecc41e3ad460c109baa1012d69e005cdc916e3cd24
+size 35925
diff --git a/crates/egui_demo_lib/tests/snapshots/text_selection_0.png b/crates/egui_demo_lib/tests/snapshots/text_selection_0.png
index 7930dff48..a6d590fdf 100644
--- a/crates/egui_demo_lib/tests/snapshots/text_selection_0.png
+++ b/crates/egui_demo_lib/tests/snapshots/text_selection_0.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:344d90928510855dc718a2e36e31a97f084f1163ab750d0217fb8620469b621a
-size 5276
+oid sha256:16e993bb27d32162fcf573cc4d977af775e6e0b94373fc5e8e1a9890453e508c
+size 5278
diff --git a/crates/egui_demo_lib/tests/snapshots/text_selection_1.png b/crates/egui_demo_lib/tests/snapshots/text_selection_1.png
index 8691211cb..3506845cb 100644
--- a/crates/egui_demo_lib/tests/snapshots/text_selection_1.png
+++ b/crates/egui_demo_lib/tests/snapshots/text_selection_1.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:60449af267336663304e44e254d0984e037bebfa2d1efdf32234cab4374e8c79
-size 5301
+oid sha256:79676693e9f1804c7e0a32ffa9bec3bde281446ffc184b55a1a3fcf34074ac34
+size 5304
diff --git a/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x1.png b/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x1.png
index 4495bf173..5ea006f1f 100644
--- a/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x1.png
+++ b/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x1.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ef245aae271ccae628bb4171f7e601194c77fd18888ef2ea829bea75bd38b0e5
-size 64965
+oid sha256:8c0054dd1717833ae6f19726b58bffbf70bd4dc784b5f2774b194800a3adffed
+size 64973
diff --git a/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x2.png b/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x2.png
index 7c47f522d..c37f49163 100644
--- a/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x2.png
+++ b/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x2.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e621561567539ff24b4d22b53b65fac6cddae71d92fccd7800a90972a6de3e0e
-size 151100
+oid sha256:9be7321d8184c3d06cfeb54410c1f839892c4f836767e9b1950e70306cde6c54
+size 151090
diff --git a/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x1.png b/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x1.png
index 520895ff5..54f2d37fd 100644
--- a/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x1.png
+++ b/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x1.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e6c2d538be7971169bbc4473945e6815eac8c5dd6372bc1f1897a032b6bca12b
-size 59962
+oid sha256:f07c25c053e9c4d5f7416cc00e101e13b7007b65c46ba13d0853d95ca43fddc4
+size 59950
diff --git a/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x2.png b/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x2.png
index 90311fddc..318fb89e4 100644
--- a/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x2.png
+++ b/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x2.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d705af99624cd2824cd1f520fa05481ac67b8913feebae836db7b99ac60cb466
-size 145841
+oid sha256:b6a9bc30b4d6ed100555ee553554848d20d93f25643e72eeef1826483ed307d9
+size 145940
diff --git a/crates/egui_kittest/tests/snapshots/combobox_closed.png b/crates/egui_kittest/tests/snapshots/combobox_closed.png
index 073ae79a3..7df09f4bd 100644
--- a/crates/egui_kittest/tests/snapshots/combobox_closed.png
+++ b/crates/egui_kittest/tests/snapshots/combobox_closed.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:00fb02e0cc2c1454d3a3dc0635be24086234c2bc5e2c9fd73741b179622e16d6
-size 4514
+oid sha256:698d1e9ecf490e04fb58ebf81cf9c633be29712abe172a6e6adfdc7fe442732d
+size 4517
diff --git a/crates/egui_kittest/tests/snapshots/combobox_opened.png b/crates/egui_kittest/tests/snapshots/combobox_opened.png
index 78e1baaca..20dd3e232 100644
--- a/crates/egui_kittest/tests/snapshots/combobox_opened.png
+++ b/crates/egui_kittest/tests/snapshots/combobox_opened.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d8757e2db9a3892d9347495ad59f14d2bd9164a9ba258375a53c9faf8176b597
-size 8016
+oid sha256:84e857521c20ea2458d9f9d724578e0495c06e75571c25104bf64a0be0be617d
+size 8028
diff --git a/crates/egui_kittest/tests/snapshots/menu/closed_hovered.png b/crates/egui_kittest/tests/snapshots/menu/closed_hovered.png
index 2a4621b0e..c498163ee 100644
--- a/crates/egui_kittest/tests/snapshots/menu/closed_hovered.png
+++ b/crates/egui_kittest/tests/snapshots/menu/closed_hovered.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:38ee4acc23d9c66f127d377ac8a0dd3b683a1465ca319fba092f6d3cdff8c266
-size 11166
+oid sha256:aac8c973f26d03c25155f0454185dc3ab27fffae1c63443e36f07c49fb0828bf
+size 11183
diff --git a/crates/egui_kittest/tests/snapshots/menu/opened.png b/crates/egui_kittest/tests/snapshots/menu/opened.png
index c698cdb4b..4ef240cc9 100644
--- a/crates/egui_kittest/tests/snapshots/menu/opened.png
+++ b/crates/egui_kittest/tests/snapshots/menu/opened.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ac1941f5eab71bfad020132eae47e1995efa17410b7861aa9f260032e5b0472c
-size 21785
+oid sha256:8dd0d91d0866848e7965e88223ff3ddae2231728197fbcd3fb5b1a6b034e179d
+size 21804
diff --git a/crates/egui_kittest/tests/snapshots/menu/submenu.png b/crates/egui_kittest/tests/snapshots/menu/submenu.png
index f277511c1..20c6bed89 100644
--- a/crates/egui_kittest/tests/snapshots/menu/submenu.png
+++ b/crates/egui_kittest/tests/snapshots/menu/submenu.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b1f1a4dd9de1d8405c527c7f8f04b42ed9d403d0ec507bb3ff650a6896f28df0
-size 28628
+oid sha256:11d0081c272986e6fbd00cde05c0931321bc9670d6a0fa3a650323cd7b56d795
+size 28667
diff --git a/crates/egui_kittest/tests/snapshots/menu/subsubmenu.png b/crates/egui_kittest/tests/snapshots/menu/subsubmenu.png
index dfc2b707c..01a316007 100644
--- a/crates/egui_kittest/tests/snapshots/menu/subsubmenu.png
+++ b/crates/egui_kittest/tests/snapshots/menu/subsubmenu.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:af05a9b66340e0c128d823d3935a23bcf17cfeac02a822e7277234a9c8eb26e0
-size 33393
+oid sha256:6fc08e05c0ab0e167503324fb7c82777afd5866384ae8bbacb9b933f717feb56
+size 33412
diff --git a/crates/egui_kittest/tests/snapshots/readme_example.png b/crates/egui_kittest/tests/snapshots/readme_example.png
index 050a4a43e..55a13d3e4 100644
--- a/crates/egui_kittest/tests/snapshots/readme_example.png
+++ b/crates/egui_kittest/tests/snapshots/readme_example.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1dd1f5013587463f002b1becac1560876c462295dbe5dfbb1a9dbce58991e53d
-size 2209
+oid sha256:57211d5ac8021223ed288b9fd6f651ed901ec91599ed67d54ac540f3a2037937
+size 2205
diff --git a/crates/egui_kittest/tests/snapshots/should_wait_for_images.png b/crates/egui_kittest/tests/snapshots/should_wait_for_images.png
index 6ceffde99..461a2e695 100644
--- a/crates/egui_kittest/tests/snapshots/should_wait_for_images.png
+++ b/crates/egui_kittest/tests/snapshots/should_wait_for_images.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cfc03625c268f0ae067d2f4521a8668b47e4bc8525350d77a480840a09cd5083
-size 2046
+oid sha256:4ae52d6761a4d0b95b38ca4ca34c10751eef1ab2a54a62786c55bee3a3522ba1
+size 2050
diff --git a/crates/egui_kittest/tests/snapshots/test_masking.png b/crates/egui_kittest/tests/snapshots/test_masking.png
index 5bf5dd6fa..6473e407e 100644
--- a/crates/egui_kittest/tests/snapshots/test_masking.png
+++ b/crates/egui_kittest/tests/snapshots/test_masking.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:be0bd449166878ced27eff4966d1741731e926f9baabe8b590375c20103036dd
-size 5527
+oid sha256:7ddac0bff10e6699c0ab2d9ea3679d5047d6099b7ba3540d1ebc144361f07d86
+size 5517
diff --git a/crates/egui_kittest/tests/snapshots/test_scroll_initial.png b/crates/egui_kittest/tests/snapshots/test_scroll_initial.png
index 64ed153a6..e03db834f 100644
--- a/crates/egui_kittest/tests/snapshots/test_scroll_initial.png
+++ b/crates/egui_kittest/tests/snapshots/test_scroll_initial.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6154c8bb550575bcb9fa0bba06da4d47079a00dffc5754b62ef2a6e7529e2090
-size 7489
+oid sha256:59939d3347679ff27c1de500a559cdc0e6387f633c86ec7ce51f2a36cd92547b
+size 7511
diff --git a/crates/egui_kittest/tests/snapshots/test_shrink.png b/crates/egui_kittest/tests/snapshots/test_shrink.png
index e4ff540f4..de27685a8 100644
--- a/crates/egui_kittest/tests/snapshots/test_shrink.png
+++ b/crates/egui_kittest/tests/snapshots/test_shrink.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:888f8a4d995d718a9a158e563d8ac1434775660b33aebb5f34feea54ffd12600
-size 2830
+oid sha256:db6f35e7dabe8f6d3766df022e5643f8461c3c2476959682622b793d59bf7c40
+size 2833
diff --git a/crates/egui_kittest/tests/snapshots/test_tooltip_hidden.png b/crates/egui_kittest/tests/snapshots/test_tooltip_hidden.png
index e4ff540f4..de27685a8 100644
--- a/crates/egui_kittest/tests/snapshots/test_tooltip_hidden.png
+++ b/crates/egui_kittest/tests/snapshots/test_tooltip_hidden.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:888f8a4d995d718a9a158e563d8ac1434775660b33aebb5f34feea54ffd12600
-size 2830
+oid sha256:db6f35e7dabe8f6d3766df022e5643f8461c3c2476959682622b793d59bf7c40
+size 2833
diff --git a/crates/egui_kittest/tests/snapshots/test_tooltip_shown.png b/crates/egui_kittest/tests/snapshots/test_tooltip_shown.png
index d6053700b..7396758ea 100644
--- a/crates/egui_kittest/tests/snapshots/test_tooltip_shown.png
+++ b/crates/egui_kittest/tests/snapshots/test_tooltip_shown.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:037f3e356d32e1a2c32767460399f919452bff0933e1db7aa113e7e2bdb083f0
-size 4927
+oid sha256:d785e2073627f33a2e7a23a47e0e0b8ca9570f45d4de3d8b545b473c1a9e75b5
+size 4940
diff --git a/crates/epaint/Cargo.toml b/crates/epaint/Cargo.toml
index 9d6e3eade..705f1f6a9 100644
--- a/crates/epaint/Cargo.toml
+++ b/crates/epaint/Cargo.toml
@@ -63,6 +63,7 @@ ecolor.workspace = true
ahash.workspace = true
font-types.workspace = true
+harfrust.workspace = true
log.workspace = true
nohash-hasher.workspace = true
parking_lot.workspace = true # Using parking_lot over std::sync::Mutex gives 50% speedups in some real-world scenarios.
@@ -70,6 +71,8 @@ profiling.workspace = true
self_cell.workspace = true
skrifa.workspace = true
smallvec.workspace = true
+unicode-general-category.workspace = true
+unicode-segmentation.workspace = true
vello_cpu.workspace = true
#! ### Optional dependencies
diff --git a/crates/epaint/src/text/font.rs b/crates/epaint/src/text/font.rs
index 61f9f9f2f..48659fbe9 100644
--- a/crates/epaint/src/text/font.rs
+++ b/crates/epaint/src/text/font.rs
@@ -2,10 +2,7 @@
use emath::{GuiRounding as _, OrderedFloat, Vec2, vec2};
use self_cell::self_cell;
-use skrifa::{
- MetadataProvider as _,
- raw::{TableProvider as _, tables::kern::SubtableKind},
-};
+use skrifa::{GlyphId, MetadataProvider as _};
use std::collections::BTreeMap;
use vello_cpu::{color, kurbo};
@@ -44,12 +41,10 @@ impl UvRect {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct GlyphInfo {
- /// Used for pair-kerning.
- ///
/// Doesn't need to be unique.
///
/// Is `None` for a special "invisible" glyph.
- pub(crate) id: Option,
+ pub(crate) id: Option,
/// In [`skrifa`]s "unscaled" coordinate system.
pub advance_width_unscaled: OrderedFloat,
@@ -124,17 +119,8 @@ impl SubpixelBin {
}
}
-#[derive(Clone, Copy, Debug, PartialEq, Default)]
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct GlyphAllocation {
- /// Used for pair-kerning.
- ///
- /// Doesn't need to be unique.
- /// Use [`skrifa::GlyphId::NOTDEF`] if you just want to have an id, and don't care.
- pub(crate) id: skrifa::GlyphId,
-
- /// Unit: screen pixels.
- pub advance_width_px: f32,
-
/// UV rectangle for drawing.
pub uv_rect: UvRect,
}
@@ -145,7 +131,7 @@ struct GlyphCacheKey(u64);
impl nohash_hasher::IsEnabled for GlyphCacheKey {}
impl GlyphCacheKey {
- fn new(glyph_id: skrifa::GlyphId, metrics: &StyledMetrics, bin: SubpixelBin) -> Self {
+ fn new(glyph_id: GlyphId, metrics: &StyledMetrics, bin: SubpixelBin) -> Self {
let StyledMetrics {
pixels_per_point,
px_scale_factor,
@@ -198,12 +184,10 @@ impl FontCell {
&mut self,
atlas: &mut TextureAtlas,
metrics: &StyledMetrics,
- glyph_info: &GlyphInfo,
+ glyph_id: GlyphId,
bin: SubpixelBin,
location: skrifa::instance::LocationRef<'_>,
) -> Option {
- let glyph_id = glyph_info.id?;
-
debug_assert!(
glyph_id != skrifa::GlyphId::NOTDEF,
"Can't allocate glyph for id 0"
@@ -288,11 +272,7 @@ impl FontCell {
}
};
- Some(GlyphAllocation {
- id: glyph_id,
- advance_width_px: glyph_info.advance_width_unscaled.0 * metrics.px_scale_factor,
- uv_rect,
- })
+ Some(GlyphAllocation { uv_rect })
}
}
@@ -337,6 +317,10 @@ pub struct FontFace {
font: FontCell,
tweak: FontTweak,
+ /// Cached `harfrust` shaper data (parsed GSUB/GPOS tables).
+ /// `ShaperData` is `Copy` — lives outside the `self_cell`.
+ shaper_data: harfrust::ShaperData,
+
glyph_info_cache: ahash::HashMap,
glyph_alloc_cache: ahash::HashMap,
}
@@ -393,10 +377,13 @@ impl FontFace {
})
})?;
+ let shaper_data = harfrust::ShaperData::new(&font.borrow_dependent().skrifa);
+
Ok(Self {
name,
font,
tweak,
+ shaper_data,
glyph_info_cache: Default::default(),
glyph_alloc_cache: Default::default(),
})
@@ -483,7 +470,7 @@ impl FontFace {
let glyph_id = font_data
.charmap
.map(c)
- .filter(|id| *id != skrifa::GlyphId::NOTDEF)?;
+ .filter(|id| *id != GlyphId::NOTDEF)?;
let glyph_info = GlyphInfo {
id: Some(glyph_id),
@@ -497,38 +484,6 @@ impl FontFace {
Some(glyph_info)
}
- #[inline]
- pub(super) fn pair_kerning_pixels(
- &self,
- metrics: &StyledMetrics,
- last_glyph_id: skrifa::GlyphId,
- glyph_id: skrifa::GlyphId,
- ) -> f32 {
- let skrifa_font = &self.font.borrow_dependent().skrifa;
- let Ok(kern) = skrifa_font.kern() else {
- return 0.0;
- };
- kern.subtables()
- .find_map(|st| match st.ok()?.kind().ok()? {
- SubtableKind::Format0(table_ref) => table_ref.kerning(last_glyph_id, glyph_id),
- SubtableKind::Format1(_) => None,
- SubtableKind::Format2(subtable2) => subtable2.kerning(last_glyph_id, glyph_id),
- SubtableKind::Format3(table_ref) => table_ref.kerning(last_glyph_id, glyph_id),
- })
- .unwrap_or_default() as f32
- * metrics.px_scale_factor
- }
-
- #[inline]
- pub fn pair_kerning(
- &self,
- metrics: &StyledMetrics,
- last_glyph_id: skrifa::GlyphId,
- glyph_id: skrifa::GlyphId,
- ) -> f32 {
- self.pair_kerning_pixels(metrics, last_glyph_id, glyph_id) / metrics.pixels_per_point
- }
-
#[inline(always)]
pub fn styled_metrics(
&self,
@@ -571,51 +526,67 @@ impl FontFace {
}
}
+ pub(crate) fn skrifa_font_ref(&self) -> &skrifa::FontRef<'_> {
+ &self.font.borrow_dependent().skrifa
+ }
+
+ pub(crate) fn tweak(&self) -> &FontTweak {
+ &self.tweak
+ }
+
+ pub(crate) fn shaper_data(&self) -> &harfrust::ShaperData {
+ &self.shaper_data
+ }
+
pub fn allocate_glyph(
&mut self,
atlas: &mut TextureAtlas,
metrics: &StyledMetrics,
- glyph_info: GlyphInfo,
- chr: char,
- h_pos: f32,
+ shaped: &ShapedGlyph,
) -> (GlyphAllocation, i32) {
- let advance_width_px = glyph_info.advance_width_unscaled.0 * metrics.px_scale_factor;
+ let ShapedGlyph {
+ glyph_id,
+ h_pos,
+ is_cjk,
+ } = *shaped;
- let Some(glyph_id) = glyph_info.id else {
- // Invisible.
- return (GlyphAllocation::default(), h_pos as i32);
- };
+ if glyph_id == GlyphId::NOTDEF {
+ // invisible
+ return (GlyphAllocation::default(), h_pos.round() as i32);
+ }
- // CJK scripts contain a lot of characters and could hog the glyph atlas if we stored 4 subpixel offsets per
- // glyph.
- let (h_pos_round, bin) = if is_cjk(chr) {
+ let (h_pos_round, bin) = if is_cjk {
+ // CJK scripts contain a lot of characters and could hog the glyph atlas
+ // if we stored 4 subpixel offsets per glyph.
(h_pos.round() as i32, SubpixelBin::Zero)
} else {
SubpixelBin::new(h_pos)
};
- let entry = match self
- .glyph_alloc_cache
- .entry(GlyphCacheKey::new(glyph_id, metrics, bin))
- {
- std::collections::hash_map::Entry::Occupied(glyph_alloc) => {
- let mut glyph_alloc = *glyph_alloc.get();
- glyph_alloc.advance_width_px = advance_width_px; // Hack to get `\t` and thin space to work, since they use the same glyph id as ` ` (space).
- return (glyph_alloc, h_pos_round);
- }
- std::collections::hash_map::Entry::Vacant(entry) => entry,
- };
+ let cache_key = GlyphCacheKey::new(glyph_id, metrics, bin);
- let allocation = self
- .font
- .allocate_glyph_uncached(atlas, metrics, &glyph_info, bin, (&metrics.location).into())
- .unwrap_or_default();
+ let alloc = *self.glyph_alloc_cache.entry(cache_key).or_insert_with(|| {
+ self.font
+ .allocate_glyph_uncached(atlas, metrics, glyph_id, bin, (&metrics.location).into())
+ .unwrap_or_default()
+ });
- entry.insert(allocation);
- (allocation, h_pos_round)
+ (alloc, h_pos_round)
}
}
+/// Positioning info for a single glyph, ready for atlas allocation.
+#[derive(Clone, Copy, Debug)]
+pub(crate) struct ShapedGlyph {
+ pub glyph_id: GlyphId,
+
+ /// Horizontal position of the glyph origin, in physical pixels.
+ pub h_pos: f32,
+
+ /// CJK glyphs skip subpixel positioning to save atlas space.
+ pub is_cjk: bool,
+}
+
// TODO(emilk): rename?
/// Wrapper over multiple [`FontFace`] (e.g. a primary + fallbacks for emojis)
pub struct Font<'a> {
diff --git a/crates/epaint/src/text/fonts.rs b/crates/epaint/src/text/fonts.rs
index 5099e0085..135ddb6d5 100644
--- a/crates/epaint/src/text/fonts.rs
+++ b/crates/epaint/src/text/fonts.rs
@@ -765,6 +765,9 @@ pub struct FontsImpl {
fonts_by_id: nohash_hasher::IntMap,
fonts_by_name: ahash::HashMap,
family_cache: ahash::HashMap,
+
+ /// Recycled `harfrust` shaping buffer to avoid per-layout allocations.
+ shape_buffer: Option,
}
impl FontsImpl {
@@ -798,6 +801,7 @@ impl FontsImpl {
fonts_by_id,
fonts_by_name,
family_cache: Default::default(),
+ shape_buffer: Some(harfrust::UnicodeBuffer::new()),
}
}
@@ -805,6 +809,16 @@ impl FontsImpl {
self.atlas.options()
}
+ /// Take the recycled shaping buffer (or create a new one if already taken).
+ pub fn take_shape_buffer(&mut self) -> harfrust::UnicodeBuffer {
+ self.shape_buffer.take().unwrap_or_default()
+ }
+
+ /// Return a shaping buffer for reuse.
+ pub fn return_shape_buffer(&mut self, buffer: harfrust::UnicodeBuffer) {
+ self.shape_buffer = Some(buffer);
+ }
+
/// Get the right font implementation from [`FontFamily`].
pub fn font(&mut self, family: &FontFamily) -> Font<'_> {
let cached_family = self.family_cache.entry(family.clone()).or_insert_with(|| {
diff --git a/crates/epaint/src/text/text_layout.rs b/crates/epaint/src/text/text_layout.rs
index 0233c1c58..0f3089292 100644
--- a/crates/epaint/src/text/text_layout.rs
+++ b/crates/epaint/src/text/text_layout.rs
@@ -8,15 +8,35 @@ use crate::{
Color32, Mesh, Stroke, Vertex,
stroke::PathStroke,
text::{
- font::{StyledMetrics, is_cjk, is_cjk_break_allowed},
+ TAB_SIZE,
+ font::{StyledMetrics, UvRect, is_cjk, is_cjk_break_allowed},
fonts::FontFaceKey,
},
};
-use super::{FontsImpl, Galley, Glyph, LayoutJob, LayoutSection, PlacedRow, Row, RowVisuals};
+use super::{
+ FontsImpl, Galley, Glyph, LayoutJob, LayoutSection, PlacedRow, Row, RowVisuals,
+ VariationCoords,
+ font::{Font, FontFace, ShapedGlyph},
+};
// ----------------------------------------------------------------------------
+/// Returns `true` if the character is a Unicode combining mark (categories Mn, Mc, Me).
+///
+/// These characters modify the preceding base character and should not be
+/// rendered as standalone replacement glyphs when the shaper can't handle them.
+#[inline]
+fn is_combining_mark(c: char) -> bool {
+ use unicode_general_category::{GeneralCategory, get_general_category};
+ matches!(
+ get_general_category(c),
+ GeneralCategory::NonspacingMark
+ | GeneralCategory::SpacingMark
+ | GeneralCategory::EnclosingMark
+ )
+}
+
/// Represents GUI scale and convenience methods for rounding to pixels.
#[derive(Clone, Copy)]
struct PointScale {
@@ -98,15 +118,21 @@ pub fn layout(fonts: &mut FontsImpl, pixels_per_point: f32, job: Arc)
// For most of this we ignore the y coordinate:
let mut paragraphs = vec![Paragraph::from_section_index(0)];
- for (section_index, section) in job.sections.iter().enumerate() {
- layout_section(
- fonts,
- pixels_per_point,
- &job,
- section_index as u32,
- section,
- &mut paragraphs,
- );
+ {
+ let mut shape_buffer = fonts.take_shape_buffer();
+ for (section_index, section) in job.sections.iter().enumerate() {
+ let mut font = fonts.font(§ion.format.font_id.family);
+ shape_buffer = layout_section(
+ &mut font,
+ shape_buffer,
+ pixels_per_point,
+ &job,
+ section_index as u32,
+ section,
+ &mut paragraphs,
+ );
+ }
+ fonts.return_shape_buffer(shape_buffer);
}
let point_scale = PointScale::new(pixels_per_point);
@@ -144,21 +170,198 @@ pub fn layout(fonts: &mut FontsImpl, pixels_per_point: f32, job: Arc)
galley_from_rows(point_scale, job, rows, elided, intrinsic_size)
}
+/// Shared context for emitting shaped glyphs into a [`Paragraph`].
+struct ShapingContext {
+ pixels_per_point: f32,
+ font_size: f32,
+ line_height: f32,
+ extra_letter_spacing: f32,
+ section_index: u32,
+ font_metrics: StyledMetrics,
+ is_first_glyph_in_section: bool,
+ prev_cluster: Option,
+}
+
+impl ShapingContext {
+ fn glyph(
+ &self,
+ chr: char,
+ physical_x: i32,
+ advance_width_px: f32,
+ face_metrics: &StyledMetrics,
+ uv_rect: UvRect,
+ ) -> Glyph {
+ Glyph {
+ chr,
+ pos: pos2(physical_x as f32 / self.pixels_per_point, f32::NAN),
+ advance_width: advance_width_px / self.pixels_per_point,
+ line_height: self.line_height,
+ font_face_height: face_metrics.row_height,
+ font_face_ascent: face_metrics.ascent,
+ font_height: self.font_metrics.row_height,
+ font_ascent: self.font_metrics.ascent,
+ uv_rect,
+ section_index: self.section_index,
+ first_vertex: 0,
+ }
+ }
+}
+
+/// Produced by [`segment_into_runs`] for text shaping.
+#[derive(Debug)]
+struct TextRun {
+ /// Which font face should shape this run.
+ font_key: FontFaceKey,
+
+ /// Byte range within the section text.
+ byte_range: std::ops::Range,
+}
+
+/// Emit shaped glyphs from a [`harfrust::GlyphBuffer`] into a [`Paragraph`].
+fn layout_shaped_run(
+ font: &mut Font<'_>,
+ run: &TextRun,
+ run_text: &str,
+ glyph_buffer: &harfrust::GlyphBuffer,
+ face_metrics: &StyledMetrics,
+ ctx: &mut ShapingContext,
+ paragraph: &mut Paragraph,
+) {
+ let px_scale = face_metrics.px_scale_factor;
+
+ // Reset cluster tracking — cluster values are byte offsets within run_text,
+ // so they are not comparable across runs.
+ ctx.prev_cluster = None;
+
+ for (info, pos) in glyph_buffer
+ .glyph_infos()
+ .iter()
+ .zip(glyph_buffer.glyph_positions())
+ {
+ let glyph_id = skrifa::GlyphId::new(info.glyph_id);
+ let cluster = info.cluster;
+ let mut advance_width_px = pos.x_advance as f32 * px_scale;
+ let x_offset_px = pos.x_offset as f32 * px_scale;
+ let y_offset_px = -(pos.y_offset as f32 * px_scale); // harfrust Y+ up → screen Y+ down
+
+ let chr = run_text
+ .get(cluster as usize..)
+ .and_then(|s| s.chars().next())
+ .unwrap_or('\u{FFFD}'); // Unicode Replacement Character
+
+ // Tab is a layout concept, not a glyph — the shaper doesn't know about tab stops.
+ // Override the advance width to TAB_SIZE × space width.
+ if chr == '\t' {
+ let (_, space_info) = font.glyph_info(' ');
+ let space_width_px = space_info.advance_width_unscaled.0 * px_scale;
+ advance_width_px = TAB_SIZE as f32 * space_width_px;
+ }
+
+ // Apply extra_letter_spacing only at cluster boundaries,
+ // never between glyphs within the same cluster (e.g. base + mark).
+ let is_new_cluster = ctx.prev_cluster.is_none_or(|pc| pc != cluster);
+ if !ctx.is_first_glyph_in_section && is_new_cluster {
+ paragraph.cursor_x_px += ctx.extra_letter_spacing * ctx.pixels_per_point;
+ }
+ if is_new_cluster {
+ ctx.is_first_glyph_in_section = false;
+ }
+ ctx.prev_cluster = Some(cluster);
+
+ let glyph = if glyph_id == skrifa::GlyphId::NOTDEF {
+ // The shaper couldn't map this character. Drop combining marks
+ // (Unicode category M) and duplicate NOTDEF glyphs within the same
+ // cluster — only the first base character gets a replacement glyph.
+ if is_combining_mark(chr) || !is_new_cluster {
+ continue;
+ }
+
+ // Use the fallback font face (not run.font_key which returned NOTDEF).
+ let (fallback_key, glyph_info) = font.glyph_info(chr);
+ let fallback_metrics = font
+ .fonts_by_id
+ .get(&fallback_key)
+ .map(|ff| {
+ ff.styled_metrics(ctx.pixels_per_point, ctx.font_size, &Default::default())
+ })
+ .unwrap_or_default();
+ let advance_width_px =
+ glyph_info.advance_width_unscaled.0 * fallback_metrics.px_scale_factor;
+ let (glyph_alloc, physical_x) =
+ if let Some(ff) = font.fonts_by_id.get_mut(&fallback_key) {
+ ff.allocate_glyph(
+ font.atlas,
+ &fallback_metrics,
+ &ShapedGlyph {
+ glyph_id: glyph_info.id.unwrap_or(skrifa::GlyphId::NOTDEF),
+ h_pos: paragraph.cursor_x_px,
+ is_cjk: is_cjk(chr),
+ },
+ )
+ } else {
+ Default::default()
+ };
+
+ paragraph.cursor_x_px += advance_width_px;
+
+ ctx.glyph(
+ chr,
+ physical_x,
+ advance_width_px,
+ &fallback_metrics,
+ glyph_alloc.uv_rect,
+ )
+ } else {
+ let (mut glyph_alloc, physical_x) =
+ if let Some(ff) = font.fonts_by_id.get_mut(&run.font_key) {
+ ff.allocate_glyph(
+ font.atlas,
+ face_metrics,
+ &ShapedGlyph {
+ glyph_id,
+ h_pos: paragraph.cursor_x_px + x_offset_px,
+ is_cjk: is_cjk(chr),
+ },
+ )
+ } else {
+ Default::default()
+ };
+
+ // Apply shaper y_offset — this varies per glyph instance so it
+ // is not part of the cached ShapedGlyph / GlyphAllocation.
+ glyph_alloc.uv_rect.offset.y += y_offset_px / ctx.pixels_per_point;
+
+ paragraph.cursor_x_px += advance_width_px;
+
+ ctx.glyph(
+ chr,
+ physical_x,
+ advance_width_px,
+ face_metrics,
+ glyph_alloc.uv_rect,
+ )
+ };
+ paragraph.glyphs.push(glyph);
+ }
+}
+
// Ignores the Y coordinate.
+#[must_use]
fn layout_section(
- fonts: &mut FontsImpl,
+ font: &mut Font<'_>,
+ mut shape_buffer: harfrust::UnicodeBuffer,
pixels_per_point: f32,
job: &LayoutJob,
section_index: u32,
section: &LayoutSection,
out_paragraphs: &mut Vec,
-) {
+) -> harfrust::UnicodeBuffer {
let LayoutSection {
leading_space,
byte_range,
format,
} = section;
- let mut font = fonts.font(&format.font_id.family);
+
let font_size = format.font_id.size;
let font_metrics = font.styled_metrics(pixels_per_point, font_size, &format.coords);
let line_height = section
@@ -169,76 +372,100 @@ fn layout_section(
let mut paragraph = out_paragraphs.last_mut().unwrap();
if paragraph.glyphs.is_empty() {
- paragraph.empty_paragraph_height = line_height; // TODO(emilk): replace this hack with actually including `\n` in the glyphs?
+ paragraph.empty_paragraph_height = line_height;
}
-
paragraph.cursor_x_px += leading_space * pixels_per_point;
- let mut last_glyph_id = None;
+ let section_text = &job.text[byte_range.clone()];
+ let mut ctx = ShapingContext {
+ pixels_per_point,
+ font_size,
+ line_height,
+ extra_letter_spacing,
+ section_index,
+ font_metrics,
+ is_first_glyph_in_section: paragraph.glyphs.is_empty(),
+ prev_cluster: None,
+ };
+ let mut runs = Vec::new();
- // Optimization: only recompute `ScaledMetrics` when the concrete `FontImpl` changes.
- let mut current_font = FontFaceKey::INVALID;
- let mut current_font_face_metrics = StyledMetrics::default();
-
- for chr in job.text[byte_range.clone()].chars() {
- if job.break_on_newline && chr == '\n' {
+ // Process each paragraph segment (split on newlines — the shaper can't handle them).
+ for (seg_idx, segment) in SplitOrWhole::new(section_text, job.break_on_newline).enumerate() {
+ if 0 < seg_idx {
out_paragraphs.push(Paragraph::from_section_index(section_index));
paragraph = out_paragraphs.last_mut().unwrap();
- paragraph.empty_paragraph_height = line_height; // TODO(emilk): replace this hack with actually including `\n` in the glyphs?
- } else {
- let (font_id, glyph_info) = font.glyph_info(chr);
- let mut font_face = font.fonts_by_id.get_mut(&font_id);
- if current_font != font_id {
- current_font = font_id;
- current_font_face_metrics = font_face
- .as_ref()
- .map(|font_face| {
- font_face.styled_metrics(pixels_per_point, font_size, &format.coords)
- })
- .unwrap_or_default();
- }
+ paragraph.empty_paragraph_height = line_height;
+ ctx.is_first_glyph_in_section = true;
+ }
- if let (Some(font_face), Some(last_glyph_id), Some(glyph_id)) =
- (&font_face, last_glyph_id, glyph_info.id)
- {
- paragraph.cursor_x_px += font_face.pair_kerning_pixels(
- ¤t_font_face_metrics,
- last_glyph_id,
- glyph_id,
- );
+ if segment.is_empty() {
+ continue;
+ }
- // Only apply extra_letter_spacing to glyphs after the first one:
- paragraph.cursor_x_px += extra_letter_spacing * pixels_per_point;
- }
+ segment_into_runs(font, segment, &mut runs);
- let (glyph_alloc, physical_x) = if let Some(font_face) = font_face.as_mut() {
- font_face.allocate_glyph(
- font.atlas,
- ¤t_font_face_metrics,
- glyph_info,
- chr,
- paragraph.cursor_x_px,
- )
- } else {
- Default::default()
+ let num_runs = runs.len();
+ for (run_idx, run) in runs.iter().enumerate() {
+ let run_text = &segment[run.byte_range.clone()];
+ let Some(font_face) = font.fonts_by_id.get(&run.font_key) else {
+ continue;
};
- paragraph.glyphs.push(Glyph {
- chr,
- pos: pos2(physical_x as f32 / pixels_per_point, f32::NAN),
- advance_width: glyph_alloc.advance_width_px / pixels_per_point,
- line_height,
- font_face_height: current_font_face_metrics.row_height,
- font_face_ascent: current_font_face_metrics.ascent,
- font_height: font_metrics.row_height,
- font_ascent: font_metrics.ascent,
- uv_rect: glyph_alloc.uv_rect,
- section_index,
- first_vertex: 0, // filled in later
- });
+ let face_metrics =
+ font_face.styled_metrics(pixels_per_point, font_size, &format.coords);
- paragraph.cursor_x_px += glyph_alloc.advance_width_px;
- last_glyph_id = Some(glyph_alloc.id);
+ // Set buffer flags for paragraph boundary context.
+ let mut flags = harfrust::BufferFlags::empty();
+ if run_idx == 0 {
+ flags |= harfrust::BufferFlags::BEGINNING_OF_TEXT;
+ }
+ if run_idx + 1 == num_runs {
+ flags |= harfrust::BufferFlags::END_OF_TEXT;
+ }
+
+ let glyph_buffer = shape_text(font_face, run_text, &format.coords, shape_buffer, flags);
+
+ layout_shaped_run(
+ font,
+ run,
+ run_text,
+ &glyph_buffer,
+ &face_metrics,
+ &mut ctx,
+ paragraph,
+ );
+
+ shape_buffer = glyph_buffer.clear();
+ }
+ }
+
+ shape_buffer
+}
+
+/// Iterator that either splits on `'\n'` or yields the whole string once.
+/// Avoids `Box` and `Vec<&str>` allocation.
+enum SplitOrWhole<'a> {
+ Split(std::str::Split<'a, char>),
+ Whole(std::iter::Once<&'a str>),
+}
+
+impl<'a> SplitOrWhole<'a> {
+ fn new(text: &'a str, split: bool) -> Self {
+ if split {
+ Self::Split(text.split('\n'))
+ } else {
+ Self::Whole(std::iter::once(text))
+ }
+ }
+}
+
+impl<'a> Iterator for SplitOrWhole<'a> {
+ type Item = &'a str;
+
+ fn next(&mut self) -> Option<&'a str> {
+ match self {
+ Self::Split(iter) => iter.next(),
+ Self::Whole(iter) => iter.next(),
}
}
}
@@ -479,33 +706,14 @@ fn replace_last_glyph_with_overflow_character(
.unwrap_or_default();
let overflow_glyph_x = if let Some(prev_glyph) = row.glyphs.last() {
- // Kern the overflow character properly
- let pair_kerning = font_face
- .as_mut()
- .map(|font_face| {
- if let (Some(prev_glyph_id), Some(overflow_glyph_id)) = (
- font_face.glyph_info(prev_glyph.chr).and_then(|g| g.id),
- font_face.glyph_info(overflow_character).and_then(|g| g.id),
- ) {
- font_face.pair_kerning(&font_face_metrics, prev_glyph_id, overflow_glyph_id)
- } else {
- 0.0
- }
- })
- .unwrap_or_default();
-
- prev_glyph.max_x() + extra_letter_spacing + pair_kerning
+ prev_glyph.max_x() + extra_letter_spacing
} else {
0.0 // TODO(emilk): heed paragraph leading_space 😬
};
- let replacement_glyph_width = font_face
- .as_mut()
- .and_then(|f| f.glyph_info(overflow_character))
- .map(|i| {
- i.advance_width_unscaled.0 * font_face_metrics.px_scale_factor / pixels_per_point
- })
- .unwrap_or_default();
+ let advance_width_px =
+ glyph_info.advance_width_unscaled.0 * font_face_metrics.px_scale_factor;
+ let replacement_glyph_width = advance_width_px / pixels_per_point;
// Check if we're within width budget:
if overflow_glyph_x + replacement_glyph_width <= job.effective_wrap_width()
@@ -519,9 +727,11 @@ fn replace_last_glyph_with_overflow_character(
f.allocate_glyph(
font.atlas,
&font_face_metrics,
- glyph_info,
- overflow_character,
- overflow_glyph_x * pixels_per_point,
+ &ShapedGlyph {
+ glyph_id: glyph_info.id.unwrap_or(skrifa::GlyphId::NOTDEF),
+ h_pos: overflow_glyph_x * pixels_per_point,
+ is_cjk: is_cjk(overflow_character),
+ },
)
})
.unwrap_or_default();
@@ -536,7 +746,7 @@ fn replace_last_glyph_with_overflow_character(
row.glyphs.push(Glyph {
chr: overflow_character,
pos: pos2(physical_x as f32 / pixels_per_point, f32::NAN),
- advance_width: replacement_glyph_alloc.advance_width_px / pixels_per_point,
+ advance_width: advance_width_px / pixels_per_point,
line_height,
font_face_height: font_face_metrics.row_height,
font_face_ascent: font_face_metrics.ascent,
@@ -1060,6 +1270,90 @@ impl RowBreakCandidates {
// ----------------------------------------------------------------------------
+/// Segment text into runs where each run uses a single font face.
+///
+/// Grapheme clusters are never split across runs: if a combining mark
+/// falls back to a different font than its base character, it stays
+/// with the base character's font (the shaper will handle it).
+///
+/// NOTE: Segmentation is by font face, not by Unicode script. A run may
+/// mix scripts (e.g. Latin + Cyrillic) when they share the same font.
+/// This is acceptable for scripts with similar shaping rules, but would
+/// need script-aware splitting once RTL/bidi support is added.
+///
+/// Results are appended to `out` (which is cleared first) to allow
+/// the caller to reuse the allocation across calls.
+fn segment_into_runs(font: &mut Font<'_>, text: &str, out: &mut Vec) {
+ use unicode_segmentation::UnicodeSegmentation as _;
+
+ out.clear();
+
+ for (byte_offset, grapheme_str) in text.grapheme_indices(true) {
+ let byte_end = byte_offset + grapheme_str.len();
+
+ let base_char = grapheme_str.chars().next().unwrap_or(' ');
+ let (font_key, _) = font.glyph_info(base_char);
+
+ if let Some(last_run) = out.last_mut()
+ && last_run.font_key == font_key
+ {
+ last_run.byte_range.end = byte_end;
+ continue;
+ }
+ out.push(TextRun {
+ font_key,
+ byte_range: byte_offset..byte_end,
+ });
+ }
+}
+
+/// Shape a text run and return the raw [`harfrust::GlyphBuffer`].
+///
+/// The caller should iterate `glyph_infos()` / `glyph_positions()` (both
+/// `Copy` slices) and convert font units to pixels using `metrics.px_scale_factor`.
+/// After iteration, recycle the buffer via `glyph_buffer.clear()`.
+fn shape_text(
+ font_face: &FontFace,
+ text: &str,
+ coords: &VariationCoords,
+ mut buffer: harfrust::UnicodeBuffer,
+ flags: harfrust::BufferFlags,
+) -> harfrust::GlyphBuffer {
+ let font_ref = font_face.skrifa_font_ref();
+ let tweak = font_face.tweak();
+
+ // Build shaper with variable font instance if variation coordinates are set.
+ let variations: Vec = tweak
+ .coords
+ .as_ref()
+ .iter()
+ .chain(coords.as_ref().iter())
+ .map(|&(tag, value)| harfrust::Variation { tag, value })
+ .collect();
+
+ let instance = if variations.is_empty() {
+ None
+ } else {
+ Some(harfrust::ShaperInstance::from_variations(
+ font_ref, variations,
+ ))
+ };
+
+ let shaper = font_face
+ .shaper_data()
+ .shaper(font_ref)
+ .instance(instance.as_ref())
+ .build();
+
+ buffer.set_flags(flags);
+ buffer.push_str(text);
+ buffer.guess_segment_properties();
+
+ shaper.shape(buffer, &[])
+}
+
+// ----------------------------------------------------------------------------
+
#[cfg(test)]
mod tests {
@@ -1277,4 +1571,177 @@ mod tests {
"Unexpected intrinsic size"
);
}
+
+ #[test]
+ fn test_combining_diacritics() {
+ // ɔ̃ = U+0254 (LATIN SMALL LETTER OPEN O) + U+0303 (COMBINING TILDE)
+ // With text shaping, the combining tilde should NOT produce a separate
+ // advance — it should be positioned above ɔ via GPOS anchors.
+ // Note: the default fonts don't contain U+0254, so the replacement glyph
+ // is used. The key test is that the combining mark does NOT add extra width.
+ let pixels_per_point = 1.0;
+ let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default());
+
+ let job_combined = LayoutJob::simple(
+ "ɔ\u{0303}".to_owned(),
+ FontId::proportional(14.0),
+ Color32::WHITE,
+ f32::INFINITY,
+ );
+ let galley_combined = layout(&mut fonts, pixels_per_point, job_combined.into());
+
+ let job_base = LayoutJob::simple(
+ "ɔ".to_owned(),
+ FontId::proportional(14.0),
+ Color32::WHITE,
+ f32::INFINITY,
+ );
+ let galley_base = layout(&mut fonts, pixels_per_point, job_base.into());
+
+ let width_combined = galley_combined.size().x;
+ let width_base = galley_base.size().x;
+
+ assert!(
+ (width_combined - width_base).abs() < 2.0,
+ "Combining diacritic should not add significant width. \
+ Base width: {width_base}, Combined width: {width_combined}"
+ );
+
+ let glyphs = &galley_combined.rows[0].row.glyphs;
+ assert!(!glyphs.is_empty(), "Expected at least 1 glyph for ɔ̃");
+ }
+
+ #[test]
+ fn test_shaping_basic_latin() {
+ // Basic test: shaped Latin text should produce the same number of glyphs as characters.
+ let pixels_per_point = 1.0;
+ let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default());
+
+ let job = LayoutJob::simple(
+ "Hello".to_owned(),
+ FontId::proportional(14.0),
+ Color32::WHITE,
+ f32::INFINITY,
+ );
+ let galley = layout(&mut fonts, pixels_per_point, job.into());
+
+ assert_eq!(galley.rows.len(), 1);
+ assert_eq!(galley.rows[0].row.glyphs.len(), 5);
+ assert!(galley.size().x > 0.0);
+ }
+
+ #[test]
+ fn test_shaping_empty_string() {
+ let pixels_per_point = 1.0;
+ let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default());
+
+ let job = LayoutJob::simple(
+ String::new(),
+ FontId::proportional(14.0),
+ Color32::WHITE,
+ f32::INFINITY,
+ );
+ let galley = layout(&mut fonts, pixels_per_point, job.into());
+
+ assert_eq!(galley.rows.len(), 1);
+ assert_eq!(galley.rows[0].row.glyphs.len(), 0);
+ }
+
+ #[test]
+ fn test_shaping_multiple_newlines() {
+ let pixels_per_point = 1.0;
+ let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default());
+
+ let job = LayoutJob::simple(
+ "A\n\nB".to_owned(),
+ FontId::proportional(14.0),
+ Color32::WHITE,
+ f32::INFINITY,
+ );
+ let galley = layout(&mut fonts, pixels_per_point, job.into());
+
+ assert_eq!(galley.rows.len(), 3, "Expected 3 rows for 'A\\n\\nB'");
+ assert_eq!(galley.rows[0].row.glyphs.len(), 1); // "A"
+ assert_eq!(galley.rows[1].row.glyphs.len(), 0); // empty line
+ assert_eq!(galley.rows[2].row.glyphs.len(), 1); // "B"
+ }
+
+ #[test]
+ fn test_shaping_mixed_font_fallback() {
+ // Text with both Latin and emoji should work without panicking,
+ // even though they use different font faces.
+ let pixels_per_point = 1.0;
+ let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default());
+
+ let job = LayoutJob::simple(
+ "Hi 🎉 bye".to_owned(),
+ FontId::proportional(14.0),
+ Color32::WHITE,
+ f32::INFINITY,
+ );
+ let galley = layout(&mut fonts, pixels_per_point, job.into());
+
+ assert_eq!(galley.rows.len(), 1);
+ // "Hi " (3) + "🎉" (1) + " bye" (4) = at least 8 glyphs
+ assert!(
+ galley.rows[0].row.glyphs.len() >= 8,
+ "Expected >= 8 glyphs, got {}",
+ galley.rows[0].row.glyphs.len()
+ );
+ }
+
+ #[test]
+ fn test_gpos_kerning() {
+ // GPOS kerning: pairs like "AV", "VA", "AT" should be tighter than
+ // the sum of individual character widths. Without text shaping, egui
+ // only uses the legacy `kern` table, so these pairs had diff ≈ 0.
+ // With harfrust, GPOS kerning applies proper negative adjustments.
+ let pixels_per_point = 1.0;
+ let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default());
+ let font_id = FontId::proportional(14.0);
+
+ for pair in ["AV", "VA", "AT"] {
+ let (pair_w, _, _) = measure_text(&mut fonts, pair, &font_id, pixels_per_point);
+ let chars: Vec = pair.chars().collect();
+ let (w1, _, _) = measure_text(
+ &mut fonts,
+ &chars[0].to_string(),
+ &font_id,
+ pixels_per_point,
+ );
+ let (w2, _, _) = measure_text(
+ &mut fonts,
+ &chars[1].to_string(),
+ &font_id,
+ pixels_per_point,
+ );
+ let sum = w1 + w2;
+ let kern_adjustment = sum - pair_w;
+
+ assert!(
+ kern_adjustment > 0.5,
+ "GPOS kerning for '{pair}': expected pair to be noticeably tighter \
+ than sum of individuals. pair_width={pair_w:.2}, sum={sum:.2}, \
+ kern_adjustment={kern_adjustment:.2} (should be > 0.5)",
+ );
+ }
+ }
+
+ fn measure_text(
+ fonts: &mut FontsImpl,
+ text: &str,
+ font_id: &FontId,
+ pixels_per_point: f32,
+ ) -> (f32, usize, Vec<(char, f32)>) {
+ let job = LayoutJob::simple(
+ text.to_owned(),
+ font_id.clone(),
+ Color32::WHITE,
+ f32::INFINITY,
+ );
+ let galley = layout(fonts, pixels_per_point, job.into());
+ let glyphs = &galley.rows[0].row.glyphs;
+ let details: Vec<_> = glyphs.iter().map(|g| (g.chr, g.advance_width)).collect();
+ (galley.size().x, glyphs.len(), details)
+ }
}
diff --git a/tests/egui_tests/tests/snapshots/atom_letter_spacing.png b/tests/egui_tests/tests/snapshots/atom_letter_spacing.png
index 89fba254e..8a022896b 100644
--- a/tests/egui_tests/tests/snapshots/atom_letter_spacing.png
+++ b/tests/egui_tests/tests/snapshots/atom_letter_spacing.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4aaf541ed0245777c802d31f01edb0cc4e53ebd2f4444e094336c180b98091d3
-size 2221
+oid sha256:14a8e05b81da82b086fe1ba006a39951a8bca3ff7a2b05c5385a425383b30961
+size 2207
diff --git a/tests/egui_tests/tests/snapshots/button_shortcut.png b/tests/egui_tests/tests/snapshots/button_shortcut.png
index de7d64b4d..6ee227fca 100644
--- a/tests/egui_tests/tests/snapshots/button_shortcut.png
+++ b/tests/egui_tests/tests/snapshots/button_shortcut.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cbf68b6934dae0868bc9cf0891baf5acf110284d297cfa348e756237fca64a28
-size 1564
+oid sha256:1cdfd5e248b3a1f2053f038a4e45c68f085ddbc085a6e1719b1c4c43b18f8d6c
+size 1566
diff --git a/tests/egui_tests/tests/snapshots/grow_all.png b/tests/egui_tests/tests/snapshots/grow_all.png
index 89b96aba7..9771b6ef1 100644
--- a/tests/egui_tests/tests/snapshots/grow_all.png
+++ b/tests/egui_tests/tests/snapshots/grow_all.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:83c3e19004462b793a5929f60f8b81a795c57529bfc74c6e87890aa4b9b8d939
-size 13930
+oid sha256:d74498e867f1ede9fa5e8769afeb24d7cfdd464db7accf0e4770aa94c7860bbc
+size 13929
diff --git a/tests/egui_tests/tests/snapshots/horizontal_wrapped_multiline_row_height.png b/tests/egui_tests/tests/snapshots/horizontal_wrapped_multiline_row_height.png
index e6ac8e446..277c93280 100644
--- a/tests/egui_tests/tests/snapshots/horizontal_wrapped_multiline_row_height.png
+++ b/tests/egui_tests/tests/snapshots/horizontal_wrapped_multiline_row_height.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ef21b42f90401f6b85685e1cc37d07970b38d2b40394f53bbde5bd4f0d54fb95
-size 5340
+oid sha256:1bf4b21569bb28659808ee668be82ac89275dfbbbefba3237560aa2bcbc986b2
+size 5339
diff --git a/tests/egui_tests/tests/snapshots/horizontal_wrapped_multiline_row_height_reference.png b/tests/egui_tests/tests/snapshots/horizontal_wrapped_multiline_row_height_reference.png
index a533a8401..60aede644 100644
--- a/tests/egui_tests/tests/snapshots/horizontal_wrapped_multiline_row_height_reference.png
+++ b/tests/egui_tests/tests/snapshots/horizontal_wrapped_multiline_row_height_reference.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5025f4cb528ae5edc387149f1d14523ab4b93058f0862e775a1c2276a3e77af6
-size 5377
+oid sha256:3b2a7bfced8ffd7d0002e52f98a01585c9667bc9821bc392e00fb890fb317696
+size 5376
diff --git a/tests/egui_tests/tests/snapshots/hovering_should_preserve_text_format.png b/tests/egui_tests/tests/snapshots/hovering_should_preserve_text_format.png
index 672418f84..845dfb4ad 100644
--- a/tests/egui_tests/tests/snapshots/hovering_should_preserve_text_format.png
+++ b/tests/egui_tests/tests/snapshots/hovering_should_preserve_text_format.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3a5669c2c354c6ea42d8eaeb2eb39b65130a87807cbba8382dcc24d59790e794
-size 12181
+oid sha256:78daa3415e3012c0834819de8338dc380e262c5199f0e477b8796b6d11fe606f
+size 12212
diff --git a/tests/egui_tests/tests/snapshots/layout/atoms_image.png b/tests/egui_tests/tests/snapshots/layout/atoms_image.png
index 765e63f05..9bde044b4 100644
--- a/tests/egui_tests/tests/snapshots/layout/atoms_image.png
+++ b/tests/egui_tests/tests/snapshots/layout/atoms_image.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:24c85a987b0b80961b656f386f529b7538ddee59a030d02a0946d0f714ce7004
-size 368329
+oid sha256:c6f941a45026d7842292366b70cfa3824fe16a9f78fd745b6fcd44c48e046a36
+size 369410
diff --git a/tests/egui_tests/tests/snapshots/layout/atoms_minimal.png b/tests/egui_tests/tests/snapshots/layout/atoms_minimal.png
index 3e37969f7..6d77c9127 100644
--- a/tests/egui_tests/tests/snapshots/layout/atoms_minimal.png
+++ b/tests/egui_tests/tests/snapshots/layout/atoms_minimal.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:97b26c9abaf655fa5ef0625b8bc61042291a8ea18ecc89ea16abd3be6368c006
-size 367314
+oid sha256:a9ec7559bb6f57f446fd32f1fc342907ad4b888688195a5c147a2faaeaf5cd7a
+size 369296
diff --git a/tests/egui_tests/tests/snapshots/layout/atoms_multi_grow.png b/tests/egui_tests/tests/snapshots/layout/atoms_multi_grow.png
index 54a8a3e1c..350194332 100644
--- a/tests/egui_tests/tests/snapshots/layout/atoms_multi_grow.png
+++ b/tests/egui_tests/tests/snapshots/layout/atoms_multi_grow.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:47b09261afe84892cdb169cb99ae59c49f671e68b3e99fc170e304de9b2bf526
-size 290633
+oid sha256:f0402dcf47b05586a9792d4583a7b7c76072b2f147a57b94bc7f3ba2b3471b26
+size 291012
diff --git a/tests/egui_tests/tests/snapshots/layout/button.png b/tests/egui_tests/tests/snapshots/layout/button.png
index 635858aba..464daa5de 100644
--- a/tests/egui_tests/tests/snapshots/layout/button.png
+++ b/tests/egui_tests/tests/snapshots/layout/button.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3cbc6f95073cbbb26729d287e5fe073c76e8bddee7eef95b431a873522234297
-size 313244
+oid sha256:1bafb447c177f2bd94980c1d146a2826ecf62070fb6ee18e63e6a925e2741210
+size 314478
diff --git a/tests/egui_tests/tests/snapshots/layout/button_image.png b/tests/egui_tests/tests/snapshots/layout/button_image.png
index 6c63fb759..ce2844f8f 100644
--- a/tests/egui_tests/tests/snapshots/layout/button_image.png
+++ b/tests/egui_tests/tests/snapshots/layout/button_image.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8f14f770785d01b1673d1c8ca780bfff72e51992794dc7233cf5ec4ea99cb3e9
-size 350648
+oid sha256:eadf74cc7f7e10be804df0e7df65c232ecaed7d77c2c89197548ab7206706843
+size 351669
diff --git a/tests/egui_tests/tests/snapshots/layout/button_image_shortcut.png b/tests/egui_tests/tests/snapshots/layout/button_image_shortcut.png
index 9c74cd8be..3a8d09f95 100644
--- a/tests/egui_tests/tests/snapshots/layout/button_image_shortcut.png
+++ b/tests/egui_tests/tests/snapshots/layout/button_image_shortcut.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:231ceab75a602eedcd11f4f4ed34f38fb9d072f5cb54e135a7e02d33d257f86b
-size 433973
+oid sha256:60739a18972a5e866610ae2c8f5af719a1bbaeffcdd8c6319e783c37e28d3107
+size 435108
diff --git a/tests/egui_tests/tests/snapshots/layout/checkbox.png b/tests/egui_tests/tests/snapshots/layout/checkbox.png
index 766aedaca..1f958fd57 100644
--- a/tests/egui_tests/tests/snapshots/layout/checkbox.png
+++ b/tests/egui_tests/tests/snapshots/layout/checkbox.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2f17fe1f7b2cccaa8991559218a7f13f61e459dc8443cf0fe2d24df7e9bd2eea
-size 388959
+oid sha256:46d28fc14a4fb8e4a5fb962b17f6a1ad9b8c952453df62d49f846fda9945b409
+size 389363
diff --git a/tests/egui_tests/tests/snapshots/layout/checkbox_checked.png b/tests/egui_tests/tests/snapshots/layout/checkbox_checked.png
index 8f79ec659..3a2676aba 100644
--- a/tests/egui_tests/tests/snapshots/layout/checkbox_checked.png
+++ b/tests/egui_tests/tests/snapshots/layout/checkbox_checked.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:552a4d4933768ea1ee2323e7946f74f9ddd7e2f7b7c6d9f94bb92c8e7dd230a4
-size 416630
+oid sha256:2fb6db99b4dfa1b0c6f97799ffd72c264c02eefd803eee5737075231760c80bd
+size 417925
diff --git a/tests/egui_tests/tests/snapshots/layout/drag_value.png b/tests/egui_tests/tests/snapshots/layout/drag_value.png
index bfe289a61..105cd3453 100644
--- a/tests/egui_tests/tests/snapshots/layout/drag_value.png
+++ b/tests/egui_tests/tests/snapshots/layout/drag_value.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:339772a7974a2136b222697af2dd6e0202295d78e0720645204feb3c291481af
-size 263181
+oid sha256:f54f444c25fbd1def8d0f11d03e1fd8bde6745a2593d0029e346cbaafa584ed3
+size 264007
diff --git a/tests/egui_tests/tests/snapshots/layout/radio.png b/tests/egui_tests/tests/snapshots/layout/radio.png
index 2fbd917a8..043e6b1a7 100644
--- a/tests/egui_tests/tests/snapshots/layout/radio.png
+++ b/tests/egui_tests/tests/snapshots/layout/radio.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:275c5358d3cfcbae7dfbeae4eac6606e2f394023837da492adc85934a972203e
-size 325936
+oid sha256:5be1a82841c5d9916ad0c69eb08ca782797e42ee6f085a50ce2f5bcaa1ec917d
+size 328013
diff --git a/tests/egui_tests/tests/snapshots/layout/radio_checked.png b/tests/egui_tests/tests/snapshots/layout/radio_checked.png
index e95932c0d..6ef9b7b05 100644
--- a/tests/egui_tests/tests/snapshots/layout/radio_checked.png
+++ b/tests/egui_tests/tests/snapshots/layout/radio_checked.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8bde6a904873ec2ffd7a194b820f3d76db5cacb3c266f3cb99f1c77ca2bd69fb
-size 346473
+oid sha256:0cd7790301453097e1109a2f6600a986a12e0b02406471f12d8c1984395870e4
+size 347530
diff --git a/tests/egui_tests/tests/snapshots/layout/selectable_value.png b/tests/egui_tests/tests/snapshots/layout/selectable_value.png
index fd2daeeb0..b66e2e68a 100644
--- a/tests/egui_tests/tests/snapshots/layout/selectable_value.png
+++ b/tests/egui_tests/tests/snapshots/layout/selectable_value.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e0b87d78fce32144f1c694beb637461cb70b9127346c90d0276a877db0700291
-size 387935
+oid sha256:fd2d4946dcff38c5fbb1c3af64faa9686f93bd163f54eef0aef9c92084527671
+size 388797
diff --git a/tests/egui_tests/tests/snapshots/layout/selectable_value_selected.png b/tests/egui_tests/tests/snapshots/layout/selectable_value_selected.png
index 8ce768dae..a52c4de9a 100644
--- a/tests/egui_tests/tests/snapshots/layout/selectable_value_selected.png
+++ b/tests/egui_tests/tests/snapshots/layout/selectable_value_selected.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:77d4dd1a05771c25af933398d4f118e5e21a31b2e4db66161cf054fb1d7ebe24
-size 400911
+oid sha256:97c2f56dad8d6aa45385901f9b23a13c49c21fc5aa811ab50dcf7c8451b177dd
+size 401596
diff --git a/tests/egui_tests/tests/snapshots/layout/slider.png b/tests/egui_tests/tests/snapshots/layout/slider.png
index 83da462b7..306d2a97f 100644
--- a/tests/egui_tests/tests/snapshots/layout/slider.png
+++ b/tests/egui_tests/tests/snapshots/layout/slider.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b4071301c08f980ee26d914e4a4724b3f46f1113c62495483d9b0df980d8cbcd
-size 274770
+oid sha256:619139eb166d383cc9b35653c8c4a97c55cd21b171a24e253d923558cc0d35e1
+size 275512
diff --git a/tests/egui_tests/tests/snapshots/layout/text_edit.png b/tests/egui_tests/tests/snapshots/layout/text_edit.png
index d5d853f5e..5936c68a7 100644
--- a/tests/egui_tests/tests/snapshots/layout/text_edit.png
+++ b/tests/egui_tests/tests/snapshots/layout/text_edit.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:29363b37f1260f9f39edf9ba873f4c33c0d8a8b6670f6fc178459019539ae7e3
-size 220588
+oid sha256:260b2f77cfa51fbc5a948725d1219cfee8723362f228eb768255ee3f271faa39
+size 221505
diff --git a/tests/egui_tests/tests/snapshots/layout/text_edit_clip.png b/tests/egui_tests/tests/snapshots/layout/text_edit_clip.png
index d87f37561..251ecc9ea 100644
--- a/tests/egui_tests/tests/snapshots/layout/text_edit_clip.png
+++ b/tests/egui_tests/tests/snapshots/layout/text_edit_clip.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:94186c0b9331fd0d13284126f4f5e92e66014105fb6533422516d4fbe765e4c7
-size 372041
+oid sha256:35342ae9a83bcd19ba169c762f21f1667d9fcc781e6370b939e1781ff5a4e477
+size 372996
diff --git a/tests/egui_tests/tests/snapshots/layout/text_edit_no_clip.png b/tests/egui_tests/tests/snapshots/layout/text_edit_no_clip.png
index e65f04b1c..8adc7676b 100644
--- a/tests/egui_tests/tests/snapshots/layout/text_edit_no_clip.png
+++ b/tests/egui_tests/tests/snapshots/layout/text_edit_no_clip.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:aed677ddda9544258ddc58ed602655f6a62ab2d1d8342accd025593bbcb25e2f
-size 506926
+oid sha256:01795b279efc5c680d77817f7d0e6e9f18dc3969ec964d8d3419d0175b0f4d87
+size 512262
diff --git a/tests/egui_tests/tests/snapshots/layout/text_edit_placeholder_clip.png b/tests/egui_tests/tests/snapshots/layout/text_edit_placeholder_clip.png
index 578e4d9db..900845aff 100644
--- a/tests/egui_tests/tests/snapshots/layout/text_edit_placeholder_clip.png
+++ b/tests/egui_tests/tests/snapshots/layout/text_edit_placeholder_clip.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8ff058ef716689c309ae9806aaf08fb64eca545ef8f92ce89e1f8e9b7b7733bc
-size 330200
+oid sha256:263f38d4053119d3b5104575ceaba749d29582f6f021b7b9089054ecba4b22a0
+size 330923
diff --git a/tests/egui_tests/tests/snapshots/layout/text_edit_prefix_suffix.png b/tests/egui_tests/tests/snapshots/layout/text_edit_prefix_suffix.png
index bdcab38f2..439e89094 100644
--- a/tests/egui_tests/tests/snapshots/layout/text_edit_prefix_suffix.png
+++ b/tests/egui_tests/tests/snapshots/layout/text_edit_prefix_suffix.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cf00e99dbfdf7497688955feb8c417fab0a366588d92182eccee775abade5179
-size 361876
+oid sha256:a40004fe56075f31162e16c7c59c00d7e1b8132bbea603b3c54c4dec0875b1bb
+size 364491
diff --git a/tests/egui_tests/tests/snapshots/max_width.png b/tests/egui_tests/tests/snapshots/max_width.png
index be50f81db..cc1d4f913 100644
--- a/tests/egui_tests/tests/snapshots/max_width.png
+++ b/tests/egui_tests/tests/snapshots/max_width.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:df3c1ba38afa30d22106d21a54621c28a0de2b98f77f4d7e398f09089286ef3e
-size 8367
+oid sha256:67a7d4da3fd41cae45abc5c0dbc0257de64c8d136291b92a6885ab4d9589ff6e
+size 8388
diff --git a/tests/egui_tests/tests/snapshots/max_width_and_grow.png b/tests/egui_tests/tests/snapshots/max_width_and_grow.png
index d49489c41..abb0ceb28 100644
--- a/tests/egui_tests/tests/snapshots/max_width_and_grow.png
+++ b/tests/egui_tests/tests/snapshots/max_width_and_grow.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f5919c35a3d736e0c432b3a94d6ab2a2f936f71852b94f2f95475fa6ab5281ad
-size 8369
+oid sha256:e15a6273a919fe06f7f096f0f7f4ef23eec739841cae58c9b27bd948ea025fef
+size 8390
diff --git a/tests/egui_tests/tests/snapshots/rotated_ellipse.png b/tests/egui_tests/tests/snapshots/rotated_ellipse.png
index e32f7864c..55a51d681 100644
--- a/tests/egui_tests/tests/snapshots/rotated_ellipse.png
+++ b/tests/egui_tests/tests/snapshots/rotated_ellipse.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e8f222733524b21969834a9ccc15aa9b0a4deb1d41e1086c80750f7cdd9711c8
-size 17324
+oid sha256:7591c9001a1b4b8cf1f19d7b3efa3bb1f43f7a695c1818b602e3c1f19b179a69
+size 17299
diff --git a/tests/egui_tests/tests/snapshots/rotated_rect.png b/tests/egui_tests/tests/snapshots/rotated_rect.png
index 52255aa7f..d09ee268f 100644
--- a/tests/egui_tests/tests/snapshots/rotated_rect.png
+++ b/tests/egui_tests/tests/snapshots/rotated_rect.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fb4f1d10aa664e04da4b2e38c52cb6516a4c43a98884c9223e15266ea28ccd3d
-size 14191
+oid sha256:816105d33ea4233c62a577377a1bf447bf5022ce4df553480924aee97fc374c1
+size 14153
diff --git a/tests/egui_tests/tests/snapshots/shrink_first_text.png b/tests/egui_tests/tests/snapshots/shrink_first_text.png
index a623d8b3b..7b9ef4003 100644
--- a/tests/egui_tests/tests/snapshots/shrink_first_text.png
+++ b/tests/egui_tests/tests/snapshots/shrink_first_text.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:73b1cc01da110554dd41f4e5134f5d6d34b7e2079d5ac776f40980d616481ffc
-size 11448
+oid sha256:224d55c987c8528bb6f9d051893572fbbb36e82bb5acec8b9614784d25093af1
+size 11383
diff --git a/tests/egui_tests/tests/snapshots/shrink_last_text.png b/tests/egui_tests/tests/snapshots/shrink_last_text.png
index cda1a2add..f1fa64de7 100644
--- a/tests/egui_tests/tests/snapshots/shrink_last_text.png
+++ b/tests/egui_tests/tests/snapshots/shrink_last_text.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:00e129a40ea9815472ab9d823a1801fbdd268bd58745cad1c1c3dd91309c61fc
-size 12010
+oid sha256:cee1c5d11e895f997b95606bf2f7c789dbff11e3e95327ab6e958586c334f5b0
+size 11932
diff --git a/tests/egui_tests/tests/snapshots/sides/default_long.png b/tests/egui_tests/tests/snapshots/sides/default_long.png
index ae862c32d..695e679fc 100644
--- a/tests/egui_tests/tests/snapshots/sides/default_long.png
+++ b/tests/egui_tests/tests/snapshots/sides/default_long.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9c970aab8c09558b806c81f57fc1d695992cb9f6e735a3fb2be75997c106a141
-size 8214
+oid sha256:a1ebcf48076404bf375d9cb66fed752fab48e83adcaa3a08372340f5e68caf2f
+size 8111
diff --git a/tests/egui_tests/tests/snapshots/sides/default_long_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/default_long_fit_contents.png
index 534b55d92..308a273d6 100644
--- a/tests/egui_tests/tests/snapshots/sides/default_long_fit_contents.png
+++ b/tests/egui_tests/tests/snapshots/sides/default_long_fit_contents.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7d7c49df327cdea8cc7d6a0b7278a831574a38e8998dba0733fcae2fd44256a9
-size 8833
+oid sha256:b844510cda2e4ba73adf0fb711299d268eedbd05e8a84ea04ce73451093a3b63
+size 8786
diff --git a/tests/egui_tests/tests/snapshots/sides/shrink_left_long.png b/tests/egui_tests/tests/snapshots/sides/shrink_left_long.png
index ebf7424c3..451859fa0 100644
--- a/tests/egui_tests/tests/snapshots/sides/shrink_left_long.png
+++ b/tests/egui_tests/tests/snapshots/sides/shrink_left_long.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:46bca727290bb0fc5a9a28137385e7ee4821390d1594704ce5e0ea089f28dacf
-size 7079
+oid sha256:140fe4f323fbcd752d1f091c3095674e5392c9de72bfc43ee7032546aca5ce8a
+size 7035
diff --git a/tests/egui_tests/tests/snapshots/sides/shrink_left_long_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/shrink_left_long_fit_contents.png
index 534b55d92..308a273d6 100644
--- a/tests/egui_tests/tests/snapshots/sides/shrink_left_long_fit_contents.png
+++ b/tests/egui_tests/tests/snapshots/sides/shrink_left_long_fit_contents.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7d7c49df327cdea8cc7d6a0b7278a831574a38e8998dba0733fcae2fd44256a9
-size 8833
+oid sha256:b844510cda2e4ba73adf0fb711299d268eedbd05e8a84ea04ce73451093a3b63
+size 8786
diff --git a/tests/egui_tests/tests/snapshots/sides/shrink_right_long.png b/tests/egui_tests/tests/snapshots/sides/shrink_right_long.png
index d1cfeb533..2fa858ad9 100644
--- a/tests/egui_tests/tests/snapshots/sides/shrink_right_long.png
+++ b/tests/egui_tests/tests/snapshots/sides/shrink_right_long.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:841f69878a4b9331f8ab4730d212384a82a9de14b9fba0d6964cd3010900132a
-size 6939
+oid sha256:059ea9c691e07377307aca905d2ad70797362138228c6bd173e80951d2170ff0
+size 6833
diff --git a/tests/egui_tests/tests/snapshots/sides/shrink_right_long_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/shrink_right_long_fit_contents.png
index 534b55d92..308a273d6 100644
--- a/tests/egui_tests/tests/snapshots/sides/shrink_right_long_fit_contents.png
+++ b/tests/egui_tests/tests/snapshots/sides/shrink_right_long_fit_contents.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7d7c49df327cdea8cc7d6a0b7278a831574a38e8998dba0733fcae2fd44256a9
-size 8833
+oid sha256:b844510cda2e4ba73adf0fb711299d268eedbd05e8a84ea04ce73451093a3b63
+size 8786
diff --git a/tests/egui_tests/tests/snapshots/sides/wrap_left_long.png b/tests/egui_tests/tests/snapshots/sides/wrap_left_long.png
index be67eaf7a..757d74fb5 100644
--- a/tests/egui_tests/tests/snapshots/sides/wrap_left_long.png
+++ b/tests/egui_tests/tests/snapshots/sides/wrap_left_long.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:602bc370e3929995c9b17415b513b412e0e12433f2c2b9120c58ea63c747ed79
-size 9184
+oid sha256:b35bec0c6bd97d9941fc4ffd1072869a8875eef0080f6348b036e885c37ceeb1
+size 9073
diff --git a/tests/egui_tests/tests/snapshots/sides/wrap_left_long_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/wrap_left_long_fit_contents.png
index 534b55d92..308a273d6 100644
--- a/tests/egui_tests/tests/snapshots/sides/wrap_left_long_fit_contents.png
+++ b/tests/egui_tests/tests/snapshots/sides/wrap_left_long_fit_contents.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7d7c49df327cdea8cc7d6a0b7278a831574a38e8998dba0733fcae2fd44256a9
-size 8833
+oid sha256:b844510cda2e4ba73adf0fb711299d268eedbd05e8a84ea04ce73451093a3b63
+size 8786
diff --git a/tests/egui_tests/tests/snapshots/sides/wrap_right_long.png b/tests/egui_tests/tests/snapshots/sides/wrap_right_long.png
index cb31d61e1..0e6711016 100644
--- a/tests/egui_tests/tests/snapshots/sides/wrap_right_long.png
+++ b/tests/egui_tests/tests/snapshots/sides/wrap_right_long.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b9165daef8acd038a1527192ded0b7cd5d03f235be737308ade467df33b6c8a0
-size 9192
+oid sha256:6e478664951aa3561e74573a0e28a977c00e43db8730b086299fd33c5b4c52da
+size 9099
diff --git a/tests/egui_tests/tests/snapshots/sides/wrap_right_long_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/wrap_right_long_fit_contents.png
index 534b55d92..308a273d6 100644
--- a/tests/egui_tests/tests/snapshots/sides/wrap_right_long_fit_contents.png
+++ b/tests/egui_tests/tests/snapshots/sides/wrap_right_long_fit_contents.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7d7c49df327cdea8cc7d6a0b7278a831574a38e8998dba0733fcae2fd44256a9
-size 8833
+oid sha256:b844510cda2e4ba73adf0fb711299d268eedbd05e8a84ea04ce73451093a3b63
+size 8786
diff --git a/tests/egui_tests/tests/snapshots/size_max_size.png b/tests/egui_tests/tests/snapshots/size_max_size.png
index 499259fd4..d157d2053 100644
--- a/tests/egui_tests/tests/snapshots/size_max_size.png
+++ b/tests/egui_tests/tests/snapshots/size_max_size.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:11a987f7376f8a3174958a8c21bece8bfb7ec284077940d87038271717d2c397
-size 8655
+oid sha256:64287f55195452d41eb94729ab39ea7667abeec7cfd53c4c7e92235dbcd03bf9
+size 8675
diff --git a/tests/egui_tests/tests/snapshots/text_edit_delay_0_empty.png b/tests/egui_tests/tests/snapshots/text_edit_delay_0_empty.png
index 58b0b13f2..7f85cf977 100644
--- a/tests/egui_tests/tests/snapshots/text_edit_delay_0_empty.png
+++ b/tests/egui_tests/tests/snapshots/text_edit_delay_0_empty.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cf62a248bcec1054cbd97251e6fc429972ef2318c24b9a56698d7c80115aa57e
-size 2262
+oid sha256:570216d6ffa3cc278705582d95b96200bc3ef1608b8f2983a6ed3f8b2ee7276c
+size 2280
diff --git a/tests/egui_tests/tests/snapshots/text_edit_delay_1_h_invisible.png b/tests/egui_tests/tests/snapshots/text_edit_delay_1_h_invisible.png
index c1920bcf1..66ad3f4a4 100644
--- a/tests/egui_tests/tests/snapshots/text_edit_delay_1_h_invisible.png
+++ b/tests/egui_tests/tests/snapshots/text_edit_delay_1_h_invisible.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ef70c95f7e171984f992e1b9366b4a0fe11a4871746cb8cfaa8ee263e59de702
-size 2272
+oid sha256:e74e32fb12decf36c8685274226c29c4e748b2bf276bf6b47ba19ac9a3def66a
+size 2290
diff --git a/tests/egui_tests/tests/snapshots/text_edit_halign.png b/tests/egui_tests/tests/snapshots/text_edit_halign.png
index 29546a036..bda8964c8 100644
--- a/tests/egui_tests/tests/snapshots/text_edit_halign.png
+++ b/tests/egui_tests/tests/snapshots/text_edit_halign.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:502607c803b884e4e1640d39c97b03b0a40df93c2da328f889168e386f837f36
-size 13261
+oid sha256:f567547c446ffa75f968e0ffc505560f3b3d4171319fbe59be27dde4e553e287
+size 13273
diff --git a/tests/egui_tests/tests/snapshots/visuals/button.png b/tests/egui_tests/tests/snapshots/visuals/button.png
index e6978c70f..4978b5a3b 100644
--- a/tests/egui_tests/tests/snapshots/visuals/button.png
+++ b/tests/egui_tests/tests/snapshots/visuals/button.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9ed487544a84f9f128af550030bc7fe8a960bc70897b38f7c858440a42b6ce44
-size 11197
+oid sha256:2eb21d7b99171d249127377698225f0b2e103733864f6809785dfba169e133bf
+size 11213
diff --git a/tests/egui_tests/tests/snapshots/visuals/button_image.png b/tests/egui_tests/tests/snapshots/visuals/button_image.png
index 6cb7241bf..9d3669597 100644
--- a/tests/egui_tests/tests/snapshots/visuals/button_image.png
+++ b/tests/egui_tests/tests/snapshots/visuals/button_image.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d53f67fb3a3717f7bc5ce99b93bc21d1d6580899dfe8e1371ff22bb416af0786
-size 12114
+oid sha256:3322b616a292f685f6051d2bf9be0df28ca7472e8fc3c982cd094ca44dc47ff8
+size 12117
diff --git a/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut.png b/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut.png
index b278f6c25..41d88992d 100644
--- a/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut.png
+++ b/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e298d89e6fb434e5010d96661fca40bf119118b6b31fdd9fc13201bcd74c8ffd
-size 15149
+oid sha256:2021446525a7b1090aaa6b3f12fdd9295c67cde00de61c7f0d36838b6dfc2593
+size 15148
diff --git a/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut_selected.png b/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut_selected.png
index 9a1e15c20..3bb097aeb 100644
--- a/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut_selected.png
+++ b/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut_selected.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a0581d601f1e536298cb52bfc8a167aa37aebdf065fc910973a752c9c159223d
-size 14733
+oid sha256:e341f6d3fb3d9d09bd573584f68e4ada4e9af0dcb27cf1bc164797f62865c398
+size 14734
diff --git a/tests/egui_tests/tests/snapshots/visuals/checkbox.png b/tests/egui_tests/tests/snapshots/visuals/checkbox.png
index 29f33406f..e45ea9fb3 100644
--- a/tests/egui_tests/tests/snapshots/visuals/checkbox.png
+++ b/tests/egui_tests/tests/snapshots/visuals/checkbox.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:929d06a271e98f0c0a2a72fc63648693b22885f80beda0a7baa5858ceb6f952b
-size 13507
+oid sha256:9fd43ec4633a59798d2077d9fd3ad8292d5da66678a2d75d33c957a062d7848a
+size 13218
diff --git a/tests/egui_tests/tests/snapshots/visuals/checkbox_checked.png b/tests/egui_tests/tests/snapshots/visuals/checkbox_checked.png
index 145020884..31f84dbeb 100644
--- a/tests/egui_tests/tests/snapshots/visuals/checkbox_checked.png
+++ b/tests/egui_tests/tests/snapshots/visuals/checkbox_checked.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:880881761251b70d2c841b8aef3895e95a5eea499d2ff554d3f68b888fb167f9
-size 14571
+oid sha256:3e2252dbe6b26cc6b484d09c57a47f4ecd0d75df88f2279a7dd95ca43b597e9d
+size 14282
diff --git a/tests/egui_tests/tests/snapshots/visuals/drag_value.png b/tests/egui_tests/tests/snapshots/visuals/drag_value.png
index 7cd2d2ce8..b327692cb 100644
--- a/tests/egui_tests/tests/snapshots/visuals/drag_value.png
+++ b/tests/egui_tests/tests/snapshots/visuals/drag_value.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:60ad2d88535977244ac0fa153700489b454a582af2829dc2f41a531943a21d7a
-size 9079
+oid sha256:75e5610bd64f6beda7abb005344eff1f5ee23220272077d3b6ee5345baa616aa
+size 9095
diff --git a/tests/egui_tests/tests/snapshots/visuals/radio.png b/tests/egui_tests/tests/snapshots/visuals/radio.png
index b35eb2d51..d8d6a052a 100644
--- a/tests/egui_tests/tests/snapshots/visuals/radio.png
+++ b/tests/egui_tests/tests/snapshots/visuals/radio.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4502cc58a4085d1e0f9945d0bd1d25adeefe71094ce94a210c57f113727f3a5a
-size 11806
+oid sha256:bceb25ddc48567a79389d8333eeffa3db4f083d47488a05772602d6145faf2ea
+size 11830
diff --git a/tests/egui_tests/tests/snapshots/visuals/radio_checked.png b/tests/egui_tests/tests/snapshots/visuals/radio_checked.png
index 7bdae8cf1..c746c028e 100644
--- a/tests/egui_tests/tests/snapshots/visuals/radio_checked.png
+++ b/tests/egui_tests/tests/snapshots/visuals/radio_checked.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cdedec6788b1a5026603322db9dd9f5fa398813d8aa2c56bc60acad390110501
-size 12499
+oid sha256:30e17cfb5c21e3fd6f850e022f301787bd04d1e6453e3bd30ff695de1f61b8c1
+size 12524
diff --git a/tests/egui_tests/tests/snapshots/visuals/selectable_value.png b/tests/egui_tests/tests/snapshots/visuals/selectable_value.png
index 2f3192a74..bb2b2a32b 100644
--- a/tests/egui_tests/tests/snapshots/visuals/selectable_value.png
+++ b/tests/egui_tests/tests/snapshots/visuals/selectable_value.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:23d1cddf87ea10d6735403ea0b2a16811d4f92246415633d393c991c3bfab2a1
-size 13716
+oid sha256:b42c8d774d1ecb50f5bde1aa358a37cbb669b59d934786fb1cc4c6f0c3400701
+size 13711
diff --git a/tests/egui_tests/tests/snapshots/visuals/selectable_value_selected.png b/tests/egui_tests/tests/snapshots/visuals/selectable_value_selected.png
index 66f3df875..87163dd91 100644
--- a/tests/egui_tests/tests/snapshots/visuals/selectable_value_selected.png
+++ b/tests/egui_tests/tests/snapshots/visuals/selectable_value_selected.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e8ac8bbdf9331dbe4244aa2964adf9f49ab8981b899aee9f3200b2799cdf7bc0
-size 13731
+oid sha256:7037f694fef1211f2ea9d8e7e60836d8eb97c9242c7b396efeb8390eaf0852f1
+size 13730
diff --git a/tests/egui_tests/tests/snapshots/visuals/slider.png b/tests/egui_tests/tests/snapshots/visuals/slider.png
index 8a1b9cf30..8b758e108 100644
--- a/tests/egui_tests/tests/snapshots/visuals/slider.png
+++ b/tests/egui_tests/tests/snapshots/visuals/slider.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ff67666113e08d60f1d2310a3a5fca30316953cdabfcc4b259ee816eb498f209
-size 9900
+oid sha256:2d09706e0dbbbf6d07e39470285dc8bcd1b3c6d09bedd91cd20d86c96dba1131
+size 9911
diff --git a/tests/egui_tests/tests/snapshots/visuals/text_edit.png b/tests/egui_tests/tests/snapshots/visuals/text_edit.png
index 4719c8ce9..2cd2c737a 100644
--- a/tests/egui_tests/tests/snapshots/visuals/text_edit.png
+++ b/tests/egui_tests/tests/snapshots/visuals/text_edit.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7e1fb3fb0a00a447906aa205c27aa496dcb3d79e98aadf6092811a0514efb5a0
-size 8127
+oid sha256:bf723b58802e9cf5aefb0a06689ed2bfaa45afff9f0fc48d37e742244da097e6
+size 8149
diff --git a/tests/egui_tests/tests/snapshots/visuals/text_edit_clip.png b/tests/egui_tests/tests/snapshots/visuals/text_edit_clip.png
index 8a5999742..666364d68 100644
--- a/tests/egui_tests/tests/snapshots/visuals/text_edit_clip.png
+++ b/tests/egui_tests/tests/snapshots/visuals/text_edit_clip.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:077e7de9fdaaa222ee75f6ad620967fb1e29da37f60407d584be7141e9d0badd
-size 10143
+oid sha256:e900a4004a1fc808bf74bef7b1ece7c98e16582c40155e222c04f759d229fc70
+size 10125
diff --git a/tests/egui_tests/tests/snapshots/visuals/text_edit_no_clip.png b/tests/egui_tests/tests/snapshots/visuals/text_edit_no_clip.png
index f02b65693..fff21ac13 100644
--- a/tests/egui_tests/tests/snapshots/visuals/text_edit_no_clip.png
+++ b/tests/egui_tests/tests/snapshots/visuals/text_edit_no_clip.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f6cf861a5c1682add50f9bdee4672e5fcaf882329566097faecab5312ac509b7
-size 21419
+oid sha256:2119fd3aa9aefe8198e7b79968f7fafc4aa93294ba4c2577dc55929302067996
+size 21827
diff --git a/tests/egui_tests/tests/snapshots/visuals/text_edit_placeholder_clip.png b/tests/egui_tests/tests/snapshots/visuals/text_edit_placeholder_clip.png
index 19c231b45..0fb7a4708 100644
--- a/tests/egui_tests/tests/snapshots/visuals/text_edit_placeholder_clip.png
+++ b/tests/egui_tests/tests/snapshots/visuals/text_edit_placeholder_clip.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b022e27d7275764df45039abd26f80d69af40fb18bec98cca85565850df859ae
-size 8838
+oid sha256:02a333af5e58c53a89d436c4540579d3ea0c1e99c1cad4c019db1da34ff9de10
+size 8840
diff --git a/tests/egui_tests/tests/snapshots/visuals/text_edit_prefix_suffix.png b/tests/egui_tests/tests/snapshots/visuals/text_edit_prefix_suffix.png
index d27f6f8c4..c61f99ed0 100644
--- a/tests/egui_tests/tests/snapshots/visuals/text_edit_prefix_suffix.png
+++ b/tests/egui_tests/tests/snapshots/visuals/text_edit_prefix_suffix.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:337dcbf0b3a344c6cadaf9500376a627739e19e9c47b5da23786c98c612ef4dc
-size 10028
+oid sha256:e11dbb1d48a3eadecb5c0e36917785fa1f107e4e283ff2f76831482fe7cd2042
+size 10051