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

Code before:
/// Lay out a skewed fraction.
fn layout_skewed_frac(
    ctx: &mut MathContext,
    styles: StyleChain,
    num: &Content,
    denom: &Content,
    span: Span,
) -> SourceResult<()> {
    // Font-derived constants
    let vgap = scaled!(ctx, styles, skewed_fraction_vertical_gap);
    let hgap = scaled!(ctx, styles, skewed_fraction_horizontal_gap);
    let axis = scaled!(ctx, styles, axis_height);
    // let vgap = vgap + axis / 2.0; // LuaTeX behavior

    let num_style = style_for_numerator(styles);
    let num_frame = ctx.layout_into_frame(num, styles.chain(&num_style))?;
    let num_size = num_frame.size();
    let denom_style = style_for_denominator(styles);
    let denom_frame = ctx.layout_into_frame(denom, styles.chain(&denom_style))?;
    let denom_size = denom_frame.size();

    let short_fall = DELIM_SHORT_FALL.resolve(styles);

    // Final size of the fraction frame, save for the one exception below
    let mut fraction_height = num_size.y + denom_size.y + vgap;
    let fraction_width = num_size.x + denom_size.x + hgap;

    // Only exception: if the stretched slash is bigger than intended.
    let mut slash_frag = GlyphFragment::new_char(ctx.font, styles, '\u{2044}', span)?;
    let pre_stretch_height = slash_frag.size.y;
    slash_frag.stretch_vertical(ctx, fraction_height - short_fall);
    // If the standard slash was not stretchable, try the fraction slash
    if slash_frag.size.y == pre_stretch_height {
        slash_frag = GlyphFragment::new_char(ctx.font, styles, '/', span)?;
        slash_frag.stretch_vertical(ctx, fraction_height - short_fall);
    }
    slash_frag.center_on_axis();
    let slash_frame = slash_frag.into_frame();
    let slash_size = slash_frame.size();
    let vertical_offset = Abs::zero().max(slash_size.y - fraction_height) / 2.0;
    fraction_height.set_max(slash_size.y);

    // Build the final frame
    let mut fraction_frame = Frame::soft(Size::new(fraction_width, fraction_height));

    // Numerator
    fraction_frame.push_frame(Point::new(Abs::zero(), vertical_offset), num_frame);
    // Denominator
    fraction_frame.push_frame(
        Point::new(num_size.x + hgap, vertical_offset + num_size.y + vgap),
        denom_frame,

Review comment (suggestion):
The slash's frame could poke out the side in some exceptional situations; for example, `$ . / stretch(|, size: #1.8em) $` in Cambria.

Code after:
        .pack()
    } else {
        denom
    };
    let denom_frame = ctx.layout_into_fragment(denom, styles)?;
    ctx.push(denom_frame);

    Ok(())
}

/// Lay out a skewed fraction.
fn layout_skewed_frac(
    ctx: &mut MathContext,
    styles: StyleChain,
    num: &Content,
    denom: &Content,
    span: Span,
) -> SourceResult<()> {
    // Font-derived constants
    let constants = ctx.font().math();
    let vgap = constants.skewed_fraction_vertical_gap.resolve(styles);
    let hgap = constants.skewed_fraction_horizontal_gap.resolve(styles);
    let axis = constants.axis_height.resolve(styles);

    let num_style = style_for_numerator(styles);
    let num_frame = ctx.layout_into_frame(num, styles.chain(&num_style))?;
    let num_size = num_frame.size();
    let denom_style = style_for_denominator(styles);
    let denom_frame = ctx.layout_into_frame(denom, styles.chain(&denom_style))?;
    let denom_size = denom_frame.size();

    let short_fall = DELIM_SHORT_FALL.resolve(styles);

    // Height of the fraction frame
    // We recalculate this value below if the slash glyph overflows
    let mut fraction_height = num_size.y + denom_size.y + vgap;

    // Build the slash glyph to calculate its size
    let mut slash_frag =
        ctx.layout_into_fragment(&SymbolElem::packed('\u{2044}').spanned(span), styles)?;
    slash_frag.stretch_vertical(ctx, fraction_height - short_fall);
    slash_frag.center_on_axis();
    let slash_frame = slash_frag.into_frame();

    // Adjust the fraction height if the slash overflows
    let slash_size = slash_frame.size();
    let vertical_offset = Abs::zero().max(slash_size.y - fraction_height) / 2.0;
    fraction_height.set_max(slash_size.y);

    // Reference points for all three objects, used to place them in the frame.
    let mut slash_up_left = Point::new(num_size.x + hgap / 2.0, fraction_height / 2.0)