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

Code before:
                .stroked(FixedStroke::from_pair(text_fill, thickness)),
        };
        frame.push(line_pos, FrameItem::Shape(line, props.span));
    }

    ctx.push(FrameFragment::new(props, styles, frame));
    Ok(())
}

/// Lay out a skewed fraction.
#[typst_macros::time(name = "math skewed fraction layout", span = props.span)]
pub fn layout_skewed_fraction(
    item: &SkewedFractionItem,
    ctx: &mut MathContext,
    styles: StyleChain,
    props: &MathProperties,
) -> SourceResult<()> {
    // Font-derived constants
    let constants = ctx.font().math();
    let size = styles.resolve(TextElem::size);
    let vgap = constants.skewed_fraction_vertical_gap.at(size);
    let hgap = constants.skewed_fraction_horizontal_gap.at(size);
    let axis = constants.axis_height.at(size);

    let num_frame = ctx.layout_into_fragment(&item.numerator, styles)?.into_frame();
    let num_size = num_frame.size();
    let denom_frame = ctx.layout_into_fragment(&item.denominator, styles)?.into_frame();
    let denom_size = denom_frame.size();

    // 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
    item.slash.set_stretch_relative_to(fraction_height, Axis::Y);
    let slash_frag = ctx.layout_into_fragment(&item.slash, styles)?;
    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)
        - slash_size.to_point() / 2.0;
    let mut num_up_left = Point::with_y(vertical_offset);
    let mut denom_up_left = num_up_left + num_size.to_point() + Point::new(hgap, vgap);

    // Fraction width
    let fraction_width = (denom_up_left.x + denom_size.x)

Review comment (suggestion):
here, the gap does not yet factor in `gap_min`, but above `num_gap` and `denom_gap` do. This seems slightly inconsistent.

Code after:
                    text_fill.clone(),
                    stroke.clone().resolve(styles).unwrap_or_default(),
                ),
            None => Geometry::Line(Point::with_x(line_width))
                .stroked(FixedStroke::from_pair(text_fill, thickness)),
        };
        frame.push(line_pos, FrameItem::Shape(line, props.span));
        frame
    } else {
        let shift_up = match math_size {
            MathSize::Display => constants.stack_top_display_style_shift_up,
            _ => constants.stack_top_shift_up,
        }
        .at(size);
        let shift_down = match math_size {
            MathSize::Display => constants.stack_bottom_display_style_shift_down,
            _ => constants.stack_bottom_shift_down,
        }
        .at(size);
        let gap_min = match math_size {
            MathSize::Display => constants.stack_display_style_gap_min,
            _ => constants.stack_gap_min,
        }
        .at(size);

        let gap = (shift_up - num.descent()) + (shift_down - denom.ascent());

        let width = num.width().max(denom.width()) + 2.0 * item.padding.at(size);
        let height = num.height() + gap.max(gap_min) + denom.height();
        let size = Size::new(width, height);

        let num_pos = Point::with_x((width - num.width()) / 2.0);
        let denom_pos =
            Point::new((width - denom.width()) / 2.0, height - denom.height());

        let baseline = num.ascent() + shift_up + (gap_min - gap).max(Abs::zero()) / 2.0;
        let mut frame = Frame::soft(size);
        frame.set_baseline(baseline);
        frame.push_frame(num_pos, num);
        frame.push_frame(denom_pos, denom);
        frame
    };

    ctx.push(FrameFragment::new(props, styles, frame));
    Ok(())
}

/// Lay out a skewed fraction.
#[typst_macros::time(name = "math skewed fraction layout", span = props.span)]
pub fn layout_skewed_fraction(
    item: &SkewedFractionItem,