Add basic multi-char symbol layout

Not perfect, but should handle most cases

Co-authored-by: Max <max@mkor.je>
This commit is contained in:
T0mstone 2025-07-23 12:52:12 +02:00
parent 632186f446
commit 5e202843c1
2 changed files with 32 additions and 34 deletions

View File

@ -300,6 +300,7 @@ impl GlyphFragment {
); );
let buffer = rustybuzz::shape_with_plan(font.rusty(), &plan, buffer); let buffer = rustybuzz::shape_with_plan(font.rusty(), &plan, buffer);
// TODO: deal with multiple glyphs.
if buffer.len() != 1 { if buffer.len() != 1 {
bail!(span, "did not get a single glyph after shaping {}", text); bail!(span, "did not get a single glyph after shaping {}", text);
} }

View File

@ -129,44 +129,41 @@ pub fn layout_symbol(
ctx: &mut MathContext, ctx: &mut MathContext,
styles: StyleChain, styles: StyleChain,
) -> SourceResult<()> { ) -> SourceResult<()> {
assert!(
elem.text.len() <= 4 && elem.text.chars().count() == 1,
"TODO: layout multi-char symbol"
);
let elem_char = elem
.text
.chars()
.next()
.expect("TODO: should an empty symbol value forbidden?");
// Switch dotless char to normal when we have the dtls OpenType feature.
// This should happen before the main styling pass.
let dtls = style_dtls();
let (unstyled_c, symbol_styles) = match try_dotless(elem_char) {
Some(c) if has_dtls_feat(ctx.font) => (c, styles.chain(&dtls)),
_ => (elem_char, styles),
};
let variant = styles.get(EquationElem::variant); let variant = styles.get(EquationElem::variant);
let bold = styles.get(EquationElem::bold); let bold = styles.get(EquationElem::bold);
let italic = styles.get(EquationElem::italic); let italic = styles.get(EquationElem::italic);
let dtls = style_dtls();
let has_dtls_feat = has_dtls_feat(ctx.font);
for cluster in elem.text.graphemes(true) {
// Switch dotless char to normal when we have the dtls OpenType feature.
// This should happen before the main styling pass.
let mut enable_dtls = false;
let text: EcoString = cluster
.chars()
.flat_map(|mut c| {
if has_dtls_feat && let Some(d) = try_dotless(c) {
enable_dtls = true;
c = d;
}
to_style(c, MathStyle::select(c, variant, bold, italic))
})
.collect();
let styles = if enable_dtls { styles.chain(&dtls) } else { styles };
let style = MathStyle::select(unstyled_c, variant, bold, italic); let fragment: MathFragment =
let text: EcoString = to_style(unstyled_c, style).collect(); match GlyphFragment::new(ctx.font, styles, &text, elem.span()) {
Ok(mut glyph) => {
let fragment: MathFragment = adjust_glyph_layout(&mut glyph, ctx, styles);
match GlyphFragment::new(ctx.font, symbol_styles, &text, elem.span()) { glyph.into()
Ok(mut glyph) => { }
adjust_glyph_layout(&mut glyph, ctx, styles); Err(_) => {
glyph.into() // Not in the math font, fallback to normal inline text layout.
} // TODO: Should replace this with proper fallback in [`GlyphFragment::new`].
Err(_) => { layout_inline_text(&text, elem.span(), ctx, styles)?.into()
// Not in the math font, fallback to normal inline text layout. }
// TODO: Should replace this with proper fallback in [`GlyphFragment::new`]. };
layout_inline_text(&text, elem.span(), ctx, styles)?.into() ctx.push(fragment);
} }
};
ctx.push(fragment);
Ok(()) Ok(())
} }