Repository: typst/typst
File: crates/typst-layout/src/math/fragment.rs (Rust)

Code before:
        rustybuzz::Script::from_iso15924_tag(ttf_parser::Tag::from_bytes(b"math"))
            .unwrap(),
    );
    buffer.set_direction(rustybuzz::Direction::LeftToRight);
    buffer.set_flags(BufferFlags::REMOVE_DEFAULT_IGNORABLES);

    let plan = create_shape_plan(
        &font,
        buffer.direction(),
        buffer.script(),
        buffer.language().as_ref(),
        &features,
    );

    let buffer = rustybuzz::shape_with_plan(font.rusty(), &plan, buffer);
    match buffer.len() {
        0 => return None,
        1 => {}
        _ => {
            todo!("Not quite sure how to resolve this")
            // from origin/main:
            //  unreachable!()
            // from this branch:
            //  // TODO: deal with multiple glyphs.
            //  bail!(span, "did not get a single glyph after shaping {}", text);
        }
    }

    let info = buffer.glyph_infos()[0];
    let pos = buffer.glyph_positions()[0];
    let cluster = info.cluster as usize;
    let end = text[cluster..]
        .char_indices()
        .nth(1)
        .map(|(i, _)| i)
        .unwrap_or(text.len());

    if info.glyph_id != 0 && covers.is_none_or(|cov| cov.is_match(&text[cluster..end])) {
        let glyph = Glyph {
            id: info.glyph_id as u16,
            x_advance: font.to_em(pos.x_advance),
            x_offset: font.to_em(pos.x_offset),
            y_advance: font.to_em(pos.y_advance),
            y_offset: font.to_em(pos.y_offset),
            range: 0..text.len().saturating_as(),
            span: (Span::detached(), 0),
        };
        let c = text[cluster..].chars().next().unwrap();
        Some((c, font, glyph))
    } else {
        shape_glyph(

Review comment (suggestion):
@mkorje How should we handle this? I'm not sure this PR changes much w.r.t to main, but in principle a font can emit multiple glyphs for a single char or grapheme cluster if it wanted to (e.g. via a GSUB multiple substitution). It's just fairly unlikely to happen in a math font.

Code after:
    buffer.set_language(language.clone());
    // TODO: Use `rustybuzz::script::MATH` once
    // https://github.com/harfbuzz/rustybuzz/pull/165 is released.
    buffer.set_script(
        rustybuzz::Script::from_iso15924_tag(ttf_parser::Tag::from_bytes(b"math"))
            .unwrap(),
    );
    buffer.set_direction(rustybuzz::Direction::LeftToRight);
    buffer.set_flags(BufferFlags::REMOVE_DEFAULT_IGNORABLES);

    let plan = create_shape_plan(
        &font,
        buffer.direction(),
        buffer.script(),
        buffer.language().as_ref(),
        &features,
    );

    let buffer = rustybuzz::shape_with_plan(font.rusty(), &plan, buffer);
    match buffer.len() {
        0 => return Ok(None),
        1 => {}
        // TODO: Deal with multiple glyphs.
        _ => bail!(
            "shaping the text `{}` yielded more than one glyph", text.repr();
            hint: "please report this as a bug",
        ),
    }

    let info = buffer.glyph_infos()[0];
    let pos = buffer.glyph_positions()[0];
    let cluster = info.cluster as usize;
    let end = text[cluster..]
        .char_indices()
        .nth(1)
        .map(|(i, _)| i)
        .unwrap_or(text.len());

    if info.glyph_id != 0 && covers.is_none_or(|cov| cov.is_match(&text[cluster..end])) {
        let glyph = Glyph {
            id: info.glyph_id as u16,
            x_advance: font.to_em(pos.x_advance),
            x_offset: font.to_em(pos.x_offset),
            y_advance: font.to_em(pos.y_advance),
            y_offset: font.to_em(pos.y_offset),
            range: 0..text.len().saturating_as(),
            span: (Span::detached(), 0),
        };
        let c = text[cluster..].chars().next().unwrap();
        Ok(Some((c, font, glyph)))
    } else {