mirror of
https://github.com/emilk/egui.git
synced 2026-09-03 07:10:04 -04:00
Integrate harfrust for text shaping (#8031)
* 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. <img width="838" height="726" alt="before_main" src="https://github.com/user-attachments/assets/f0f26d5f-b117-43a6-b39c-ea40d2e73836" /> <img width="838" height="726" alt="after_harfrust" src="https://github.com/user-attachments/assets/d983e5da-486c-4f39-bd4f-5782a90c6b39" /> #### Ligatures <img width="1117" height="698" alt="before_closeup" src="https://github.com/user-attachments/assets/7a3b08b4-cf6f-45b7-98ba-07c473cd3b02" /> <img width="1117" height="698" alt="after_closeup" src="https://github.com/user-attachments/assets/6cfc5f21-d32f-4f09-be0c-59c8c553d44f" /> ### 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 <emil.ernerfeldt@gmail.com>
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bff16d453b960bb9abcdd9f72dab73f8f25da6339a0e1c310ed352f57080db93
|
||||
size 32426
|
||||
oid sha256:10d64e017d1d0eba736a4471d28b1602a0cb69d8e2ab53f4ee604b01c9343116
|
||||
size 32475
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:24f4a9745c60c0353ece5f8fc48200671dcb185f4f0b964bbe66bf4a2fe71d7a
|
||||
size 27067
|
||||
oid sha256:ab0d730ce0cf5f1d79947601def4f60c0a015e23a5dcd780df65c7ddc7ae7156
|
||||
size 27194
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:75a9cd9a3315b236c23a53e890de1a821d39c3327813d06df85ba86d2ed50cc7
|
||||
size 26887
|
||||
oid sha256:6fccbda741a056ae30a7bfd7497f7b0adfb337bdb885d247fbdfef43cc24b54c
|
||||
size 26948
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b849adf0ff9a06e1f7bfa22ef32b13224c7e62429cf675286110729156434d12
|
||||
size 76531
|
||||
oid sha256:26d247655398bae33c724ad3c3bdcab330d194093b07442708d5069e256f636b
|
||||
size 76542
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d4e33c7f817100d8414bba245ee7886354b86109f383d59e87a197e39501f0a0
|
||||
size 62604
|
||||
oid sha256:e3389491f9f5c54cfc2e295abe76ad53f223c31e9489e1d07a8323cf14fcf37d
|
||||
size 62628
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:93fcc271831167cb077f3de0a9f0e27037f9e5a2ce94e056bd6f1ede9890cb7e
|
||||
size 27818
|
||||
oid sha256:6e42e801758bb9e6130a4e94bd0857d6f254e68a7dedebec5af5cb7f7d896068
|
||||
size 27822
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d194db1705b36c1ee6189878a323a591555493c9319b7c2ddfc0cb0541055aca
|
||||
size 20948
|
||||
oid sha256:41e68fd3a679e2a6e3dd81129de5aa1ded3a8f24cc7b1f2ba0b876240d309d9b
|
||||
size 21019
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:62af1b6d248b731b0930c51e481118ae01a5d8c08f27697ff121a47fefea83bf
|
||||
size 10795
|
||||
oid sha256:3db502ec416b322e0f98e9737faa52d5d2fd308d47649710fffa0b0bc5996f52
|
||||
size 10783
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:deff441cd1d9142352f8759dff4b759f4572f0ddf93752349314da77abe4b254
|
||||
size 115028
|
||||
oid sha256:c39ae3420fe01d696a032d8d052c405c5623a9208fc673f5cf09188b1e6a539b
|
||||
size 115447
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:20ea4f93ee50c7a3585aef74c66d7700083ac1c16519b0704b70387849d9d2bc
|
||||
size 25057
|
||||
oid sha256:19322248e8335301b2ce31fc1f1352993a374dda945d227784fecea2ee831761
|
||||
size 25088
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1b72a4c0e6d441190a7a156b8bba709e81b6c1fe7b0eacedc1ee7a3bfcf881f6
|
||||
size 99297
|
||||
oid sha256:98f8865d866a6f28ae3e3a16c815770ed691a031b1d06f7d3662a7e94f564606
|
||||
size 99318
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:08c40934d4bd2a239bdcc1928d1e5eba56bac03fdded2c85cf47b020d669f07e
|
||||
size 18281
|
||||
oid sha256:39208c3c2c95f68fb37880b011f866bedd8dbccee33d163a725cb2a5cc6bb1b3
|
||||
size 18290
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:82878e4150e38fdc4b2e78203c8c661c2d9e716ab32595c298392faf6ba96105
|
||||
size 113803
|
||||
oid sha256:d251ffd6c34e4ffa7b5de7fe5ae57a2d8f48ba7c2e03711da2c3f1a3fd84648c
|
||||
size 113998
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:72d49d9a35e16e7413158ba14ce9cab762925f5f5e52fbbe16292de499a177f1
|
||||
size 25791
|
||||
oid sha256:4d959e17ee5c8a32534ab98b6f08db884b2fbf25476d8dc2dc90edc79bd87ea4
|
||||
size 25821
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bb7e3887cf12bd00ea09b297ac361562a961f64c15b28360bc87f72f270a4065
|
||||
size 51649
|
||||
oid sha256:c923f523cc77d678929f294b360f60b9f546ddec66d5317ad0eb44bd61a5f927
|
||||
size 51733
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:58cd3aba4392332a45f57c7dd90a9b5da386cb396c0c6319e7a7dae71e03ff30
|
||||
size 22563
|
||||
oid sha256:c9c98d7bfa08e22e217dd9e7031cc49e4b4486f1a9fdd223bd122be07af72365
|
||||
size 22550
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:26ffcf6b71108b82ce15d4cf3f9dd0ce9fe0b9563f02725fef1b74f40e749439
|
||||
size 47281
|
||||
oid sha256:68afa93605427e12fe527f3ca9613095664b4983f1f585a60f14bc2370c0a1f2
|
||||
size 47224
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:faedf9631149e231d510165215c24fccec50502d58000d5f893aa047a637a68f
|
||||
size 23148
|
||||
oid sha256:33959851f1bd2386fcca8fb5700133d14d90db5a8f783fbfaa9f3aebb7b0d5b2
|
||||
size 23119
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b6b4c2e55c02fa4caf5f9f8bd2d8c0311cc4cbcf1fc2f568fe112e8e6125c675
|
||||
size 65308
|
||||
oid sha256:7b918565d66594fe53ed62bb14e357d3489335f3d037ccb088f198d944eb367d
|
||||
size 65307
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3a65927cd8bd8d24e3ffbea8eb421eb22849b27dc77d36f8acd82bf5d5e63959
|
||||
size 33469
|
||||
oid sha256:f8c3c2912a3a11892e65f94792c77c79400a81d8c913109d39e8ce12f5b095c6
|
||||
size 33503
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:115398e2b4b459afc2f1c49c4e60ef3f63e562650f05581372002c93030da632
|
||||
size 38374
|
||||
oid sha256:0c2c7b0d4913b59ef932f6d6349ddab5cc8619b2e8e9a8b5eb3e055a62e6ed60
|
||||
size 38382
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9c595ee9b7ada33780178a6a35e26a98055a707f2ff99f6bb36e8db4ed819791
|
||||
size 18242
|
||||
oid sha256:9567f56f2dd030608798347e1ab755d95730ba5c5dd1721f1c61147be7216e87
|
||||
size 18304
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a46457b23b7b32694564d03b42bccac2f017a756225bc54b508bb6fe2ad8ee7b
|
||||
size 249548
|
||||
oid sha256:d19d694e6a70ab6acb45668b391751e82f7beab19f9918e23821c667e8cc9cdb
|
||||
size 249733
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c218115d305dfa6c9ab883ac6f3a21584b4840b3ba273ea765c8a8381d78935f
|
||||
size 57181
|
||||
oid sha256:9e1c73e28020371429b3e03d540f72dbf886fd40f0ba08bb194e868bbb3c95ff
|
||||
size 57230
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fadea24444c402695db6cbc9e03aef8a0ed3c5db487a324fb255d38c14f73dce
|
||||
size 19804
|
||||
oid sha256:c2facd3881e6b107a0dcce9d6e00008a3c9b0f31ad270c35357a87e487180f56
|
||||
size 19814
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f6105c95470d1342f9003ab03e71243b5e18a6f225261aee94b15f8f0501572c
|
||||
size 33542
|
||||
oid sha256:0ad81eb762150360368a97858ef30bb0d5aff72e71743fa40c3fd4d70ec84cdc
|
||||
size 33400
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f2ce9062c5d1f0b0861d5df49ae64e56ba0e6501e8bd3f8a92c53aea748be78b
|
||||
size 23629
|
||||
oid sha256:c22130891755ac095d73e0494f11ee8e89d0fd0c31a321d3afb969648ece11ef
|
||||
size 23675
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:927a497e8b6f9ce3b71dcb67086f477e19d327c163b2b8ad868af10009c2faf2
|
||||
size 172981
|
||||
oid sha256:465f33e53ebe15b776e2d6d0710f13f2453f00bab1f6ef4319b3491f1d1d3a26
|
||||
size 173487
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6ffba8bb50b42e47f855f62682f6d5ec10bf67b01d3aa2e843f6bf787f150d0d
|
||||
size 118562
|
||||
oid sha256:001f7a1310ddf37be4d9a7f56a95a3079f713b741824a348544561bb16c291fa
|
||||
size 118614
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9d8d87e4cb944def0dc28e3515243a8c1b07b9b0f88e802924d4381c1cda74db
|
||||
size 26763
|
||||
oid sha256:8105f7c2b519716cc0a45dffd5f08980f53f35c6c6b788592e1d82506cdacccc
|
||||
size 26665
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:db4c0cf1c4cdae3d416afce5c58efd1cc382be86431e547fa66bcc95a0a17ddb
|
||||
size 76364
|
||||
oid sha256:a9e83d5e83e3003830f7f719b02dd93273733a9b72d388aa42083387d02c1a20
|
||||
size 76310
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:57bf5220ae8f47485a07e9117abaaad36924d8c6c0f9e278cb05c455f342bff6
|
||||
size 70250
|
||||
oid sha256:3d46c87417c49c8462fac6c488e46b1482bbc75f70fe8f7af8391f0d5d28dac3
|
||||
size 70271
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7c964d07a39ad286a562b53cdfe514d568d91955e6c1ca06a0cb5e45dbe3977e
|
||||
size 60947
|
||||
oid sha256:4c47faa75a002577220a92efceab5c0ccee1ddaa17c2d2f3d6d1429dbf8fe718
|
||||
size 60887
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f5e9d645e1decf7624bc8f031b5e28213e64fc5f568dd3eeb1768a57fcb988c3
|
||||
size 21814
|
||||
oid sha256:9c09529c3a1c26c8f28c00fc15cc5f495842862276870c24b5ee0713954f97fc
|
||||
size 21916
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:57018beba5e4fb4f1e6de9c58bf898560b3a7669159d5bad91a4e2382ef57ce0
|
||||
size 64004
|
||||
oid sha256:9d69b9a12e777ee559a481aec012935a5bfb2ca8b0d48725ecd33e7f0880b2b8
|
||||
size 64273
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:99fa5a5cb10c7d277eafb258af6019eda24a3c96075a50db321f52a521dede92
|
||||
size 13700
|
||||
oid sha256:f6c020860fe9cb7503cea548afbf298ebb9dc620133870b528fe7508d04150c8
|
||||
size 13691
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1cc61413bcce62cc8e0a55460a974bb56ac40936cd2e5512c4a0e0c521eaaae4
|
||||
size 35874
|
||||
oid sha256:d033935ca18ebee7e3c35629233cc3e3a73766ac8c0627fcdd8a12660eed703c
|
||||
size 35873
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:999f9cc006302b8951d97b510a02f1209969c376ecc7909ed5d7b46da27c0637
|
||||
size 483753
|
||||
oid sha256:77c9058b036770a644f1bfcf9ed1ba7a29a7c98107b1823474c55ccc2880e9e7
|
||||
size 485880
|
||||
|
||||
Reference in New Issue
Block a user