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

Code before:
            .spanned(span);

        if let Some(attribution) = attribution.as_ref() {
            // Bring the attribution a bit closer to the quote.
            let gap = Spacing::Rel(Em::new(0.9).into());
            let v = VElem::new(gap).with_weak(true).pack();
            realized += v;
            realized += BlockElem::new()
                .with_body(Some(BlockBody::Content(attribution.realize(span))))
                .pack()
                .aligned(Alignment::END);
        }

        realized = PadElem::new(realized).pack();
    } else if let Some(Attribution::Label(label)) = attribution {
        realized += SpaceElem::shared().clone();
        realized += CiteElem::new(*label).pack().spanned(span);
    }

    Ok(realized)
};

const FOOTNOTE_RULE: ShowFn<FootnoteElem> = |elem, engine, styles| {
    let span = elem.span();
    let (dest, num) = elem.realize(engine, styles)?;
    let alt = FootnoteElem::alt_text(styles, &num.plain_text());
    let sup = PdfMarkerTag::Label(
        SuperElem::new(num).pack().spanned(span).linked(dest, Some(alt)),
    );
    Ok(HElem::hole().clone() + sup)
};

const FOOTNOTE_ENTRY_RULE: ShowFn<FootnoteEntry> = |elem, engine, styles| {
    let span = elem.span();
    let number_gap = Em::new(0.05);
    let (link, body) = elem.realize(engine, styles)?;
    let prefix = PdfMarkerTag::Label(SuperElem::new(link).pack().spanned(span));
    Ok(Content::sequence([
        HElem::new(elem.indent.get(styles).into()).pack(),
        prefix,
        HElem::new(number_gap.into()).with_weak(true).pack(),
        body,
    ]))
};

const OUTLINE_RULE: ShowFn<OutlineElem> = |elem, engine, styles| {
    let title = elem.realize_title(styles);
    let entries = elem.realize_flat(engine, styles)?;
    let entries = entries.into_iter().map(|entry| entry.pack());
    let body = PdfMarkerTag::OutlineBody(Content::sequence(entries));
    Ok(Content::sequence(title.into_iter().chain(Some(body))))

Review comment (suggestion):
I think the link creation could in principle now also be moved into the `elem.realize` using `DirectLinkElem`, so that it's guaranteed the same between layout and HTML.

The only thing kept out would be the `SuperElem` because of its role assignment in HTML.

Code after:
            .spanned(span);

        if let Some(attribution) = attribution.as_ref() {
            // Bring the attribution a bit closer to the quote.
            let gap = Spacing::Rel(Em::new(0.9).into());
            let v = VElem::new(gap).with_weak(true).pack();
            realized += v;
            realized += BlockElem::new()
                .with_body(Some(BlockBody::Content(attribution.realize(span))))
                .pack()
                .aligned(Alignment::END);
        }

        realized = PadElem::new(realized).pack();
    } else if let Some(Attribution::Label(label)) = attribution {
        realized += SpaceElem::shared().clone();
        realized += CiteElem::new(*label).pack().spanned(span);
    }

    Ok(realized)
};

const FOOTNOTE_RULE: ShowFn<FootnoteElem> = |elem, engine, styles| {
    // The footnote number that links to the footnote entry.
    let link = elem.realize(engine, styles)?;
    let sup = SuperElem::new(link).pack().spanned(elem.span());
    Ok(HElem::hole().clone() + PdfMarkerTag::Label(sup))
};

const FOOTNOTE_ENTRY_RULE: ShowFn<FootnoteEntry> = |elem, engine, styles| {
    let number_gap = Em::new(0.05);
    let (sup, body) = elem.realize(engine, styles)?;
    let prefix = PdfMarkerTag::Label(sup);
    Ok(Content::sequence([
        HElem::new(elem.indent.get(styles).into()).pack(),
        prefix,
        HElem::new(number_gap.into()).with_weak(true).pack(),
        body,
    ]))
};

const OUTLINE_RULE: ShowFn<OutlineElem> = |elem, engine, styles| {
    let title = elem.realize_title(styles);
    let entries = elem.realize_flat(engine, styles)?;
    let entries = entries.into_iter().map(|entry| entry.pack());
    let body = PdfMarkerTag::OutlineBody(Content::sequence(entries));
    Ok(Content::sequence(title.into_iter().chain(Some(body))))
};

const OUTLINE_ENTRY_RULE: ShowFn<OutlineEntry> = |elem, engine, styles| {
    let span = elem.span();