Repository: typst/typst
File: crates/typst/src/math/attach.rs (Rust)

Code before:
    layout!(tr, tr_x, tx_y); // post-superscript
    layout!(br, br_x, bx_y); // post-subscript
    layout!(t, t_x, t_y); // upper-limit
    layout!(b, b_x, b_y); // lower-limit

    // Done! Note that we retain the class of the base.
    ctx.push(FrameFragment::new(ctx, styles, frame).with_class(base_class));

    Ok(())
}

/// Calculate the distance each post-script extends to the right of the base's
/// width, as well as its kerning value. Requires the distance from the base's
/// baseline to each post-script's baseline to obtain the correct kerning value.
/// Returns 2 tuples of two lengths, each first containing the distance the
/// post-script extends left of the base's width and second containing the
/// post-script's kerning value. The first tuple is for the post-superscript,
/// and the second is for the post-subscript.
fn compute_post_script_widths(
    ctx: &MathContext,
    base: &MathFragment,
    [tr, br]: [&Option<MathFragment>; 2],
    (tr_shift, br_shift): (Abs, Abs),
    space_after_post_script: Abs,
) -> ((Abs, Abs), (Abs, Abs)) {
    let tr_values = if let Some(tr) = tr {
        let kern = math_kern(ctx, base, tr, tr_shift, Corner::TopRight);
        (space_after_post_script + tr.width() + kern, kern)
    } else {
        (Abs::zero(), Abs::zero())
    };

    // The base's bounding box already accounts for its italic correction, so we
    // need to shift the post-subscript left by the base's italic correction
    // (see the kerning algorithm as described in the OpenType MATH spec).
    let br_values = if let Some(br) = br {
        let kern = math_kern(ctx, base, br, br_shift, Corner::BottomRight)
            - base.italics_correction();
        (space_after_post_script + br.width() + kern, kern)
    } else {
        (Abs::zero(), Abs::zero())
    };

    (tr_values, br_values)
}

/// Calculate the distance each pre-script extends to the left of the base's
/// width. Requires the distance from the base's baseline to each pre-script's
/// baseline to obtain the correct kerning value.
/// Returns two lengths, the first being the distance the pre-superscript
/// extends left of the base's width and the second being the distance the

Review comment (refactor):
Potentially (not sure about this suggestion), the fairly frequent `if let Some(x) = x { /* Do stuff */ } else { /* Something amount of Abs::zero()s /* }` could be deduplicated with a helper function (that effectively does what `Option::map_or_default` would do if it existed).

Code after:
    // Calculate the distance each post-script extends to the right of the
    // base's width. Also calculate each post-script's kerning (we need this for
    // its position later).
    let ((tr_post_width, tr_kern), (br_post_width, br_kern)) = compute_post_script_widths(
        ctx,
        &base,
        [tr.as_ref(), br.as_ref()],
        (tx_shift, bx_shift),
        space_after_script,
    );

    // Calculate the final frame width.
    let pre_width = t_pre_width.max(b_pre_width).max(tl_pre_width).max(bl_pre_width);
    let base_width = base.width();
    let post_width = t_post_width.max(b_post_width).max(tr_post_width).max(br_post_width);
    let width = pre_width + base_width + post_width;

    // Calculate the horizontal position of each element in the final frame.
    let base_x = pre_width;
    let tl_x = pre_width - tl_pre_width + space_after_script;
    let bl_x = pre_width - bl_pre_width + space_after_script;
    let tr_x = pre_width + base_width + tr_kern;
    let br_x = pre_width + base_width + br_kern;
    let t_x = pre_width - t_pre_width;
    let b_x = pre_width - b_pre_width;

    // Create the final frame.
    let mut frame = Frame::soft(Size::new(width, height));
    frame.set_baseline(ascent);
    frame.push_frame(Point::new(base_x, base_y), base.into_frame());

    macro_rules! layout {
        ($e: ident, $x: ident, $y: ident) => {
            if let Some($e) = $e {
                frame.push_frame(Point::new($x, $y(&$e)), $e.into_frame());
            }
        };
    }

    layout!(tl, tl_x, tx_y); // pre-superscript
    layout!(bl, bl_x, bx_y); // pre-subscript
    layout!(tr, tr_x, tx_y); // post-superscript
    layout!(br, br_x, bx_y); // post-subscript
    layout!(t, t_x, t_y); // upper-limit
    layout!(b, b_x, b_y); // lower-limit

    // Done! Note that we retain the class of the base.
    ctx.push(FrameFragment::new(ctx, styles, frame).with_class(base_class));

    Ok(())
}