Skip to content

Commit 97b4299

Browse files
gpui: Do not render ligatures between different styled text runs (#43080)
An attempt to re-land #41043 Part of #5259 (as `>>>` forms a ligature that we need to break into differently colored tokens) Before: <img width="301" height="86" alt="image" src="https://github.com/user-attachments/assets/e710391a-b8ad-4343-8344-c86fc5cb86b6" /> and https://github.com/user-attachments/assets/ae77ba64-ca50-4b5d-9ee4-a7d46fcaeb34 After: <img width="1254" height="302" alt="image" src="https://github.com/user-attachments/assets/7fd5dba5-d798-4153-acf2-e38a1cb712ae" /> When certain combination of characters forms a ligature, it takes the color of the first character. Even though the runs are split already by color and other properties, the underlying font system merges the runs together. Attempts to modify color and other, unrelated to font size, parameters, did not help on macOS, hence a somewhat odd approach was taken: runs get interleaved font sizes: normal and "normal + a tiny bit more". This is the only option that helped splitting the ligatures, and seems to render fine. Release Notes: - Fixed ligatures forming between different text kinds --------- Co-authored-by: Lukas Wirth <[email protected]>
1 parent 404ee53 commit 97b4299

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed

crates/gpui/src/platform/mac/text_system.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ impl MacTextSystemState {
435435

436436
{
437437
let mut text = text;
438+
let mut break_ligature = true;
438439
for run in font_runs {
439440
let text_run;
440441
(text_run, text) = text.split_at(run.len);
@@ -444,21 +445,28 @@ impl MacTextSystemState {
444445
string.replace_str(&CFString::new(text_run), CFRange::init(utf16_start, 0));
445446
let utf16_end = string.char_len();
446447

447-
let cf_range = CFRange::init(utf16_start, utf16_end - utf16_start);
448+
let length = utf16_end - utf16_start;
449+
let cf_range = CFRange::init(utf16_start, length);
448450
let font = &self.fonts[run.font_id.0];
449451

450452
let font_metrics = font.metrics();
451453
let font_scale = font_size.0 / font_metrics.units_per_em as f32;
452454
max_ascent = max_ascent.max(font_metrics.ascent * font_scale);
453455
max_descent = max_descent.max(-font_metrics.descent * font_scale);
454456

457+
let font_size = if break_ligature {
458+
px(font_size.0.next_up())
459+
} else {
460+
font_size
461+
};
455462
unsafe {
456463
string.set_attribute(
457464
cf_range,
458465
kCTFontAttributeName,
459466
&font.native_font().clone_with_font_size(font_size.into()),
460467
);
461468
}
469+
break_ligature = !break_ligature;
462470
}
463471
}
464472
// Retrieve the glyphs from the shaped line, converting UTF16 offsets to UTF8 offsets.

crates/gpui/src/platform/windows/direct_write.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ impl DirectWriteState {
608608
let mut first_run = true;
609609
let mut ascent = Pixels::default();
610610
let mut descent = Pixels::default();
611+
let mut break_ligatures = false;
611612
for run in font_runs {
612613
if first_run {
613614
first_run = false;
@@ -616,6 +617,7 @@ impl DirectWriteState {
616617
text_layout.GetLineMetrics(Some(&mut metrics), &mut line_count as _)?;
617618
ascent = px(metrics[0].baseline);
618619
descent = px(metrics[0].height - metrics[0].baseline);
620+
break_ligatures = !break_ligatures;
619621
continue;
620622
}
621623
let font_info = &self.fonts[run.font_id.0];
@@ -636,10 +638,17 @@ impl DirectWriteState {
636638
text_layout.SetFontCollection(collection, text_range)?;
637639
text_layout
638640
.SetFontFamilyName(&HSTRING::from(&font_info.font_family), text_range)?;
639-
text_layout.SetFontSize(font_size.0, text_range)?;
641+
let font_size = if break_ligatures {
642+
font_size.0.next_up()
643+
} else {
644+
font_size.0
645+
};
646+
text_layout.SetFontSize(font_size, text_range)?;
640647
text_layout.SetFontStyle(font_info.font_face.GetStyle(), text_range)?;
641648
text_layout.SetFontWeight(font_info.font_face.GetWeight(), text_range)?;
642649
text_layout.SetTypography(&font_info.features, text_range)?;
650+
651+
break_ligatures = !break_ligatures;
643652
}
644653

645654
let mut runs = Vec::new();

0 commit comments

Comments
 (0)