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

Code before:
    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 = SuperElem::new(num).pack().spanned(span).linked(dest, Some(alt));
    Ok(HElem::hole().clone() + PdfMarkerTag::Label(sup))
};

const FOOTNOTE_ENTRY_RULE: ShowFn<FootnoteEntry> = |elem, engine, styles| {
    let span = elem.span();
    let number_gap = Em::new(0.05);
    let (dest, num, body) = elem.realize(engine, styles)?;
    let alt = num.plain_text();
    let sup = SuperElem::new(num).pack().spanned(span);
    let prefix = PdfMarkerTag::Label(
        DirectLinkElem::new(dest, sup, Some(alt)).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))))
};

const OUTLINE_ENTRY_RULE: ShowFn<OutlineEntry> = |elem, engine, styles| {
    let span = elem.span();
    let context = Context::new(None, Some(styles));
    let context = context.track();

    let prefix = elem.prefix(engine, context, span)?;
    let body = elem.body().at(span)?;
    let page = elem.page(engine, context, span)?;
    let alt = {
        let prefix = prefix.as_ref().map(|p| p.plain_text()).unwrap_or_default();
        let body = body.plain_text();
        let page_str = PageElem::local_name_in(styles);
        let page_nr = page.plain_text();
        let quotes = SmartQuotes::get(
            styles.get_ref(SmartQuoteElem::quotes),

Review comment (bug):
If I understood correctly, `realize` and the footnote entry show rules were changed to have different behavior between PDF and HTML. But I wonder if it wouldn't be fine to do the same for PDF? I suppose the superscript itself wouldn't be represented in the tag tree, right? So it'd be fine to tag a superscript of a link instead of the link itself...

I'll defer the final word on this to @saecki in case my assumption is wrong.

Code after:
};

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();
    let context = Context::new(None, Some(styles));
    let context = context.track();

    let prefix = elem.prefix(engine, context, span)?;
    let body = elem.body().at(span)?;
    let page = elem.page(engine, context, span)?;
    let alt = {
        let prefix = prefix.as_ref().map(|p| p.plain_text()).unwrap_or_default();
        let body = body.plain_text();
        let page_str = PageElem::local_name_in(styles);
        let page_nr = page.plain_text();
        let quotes = SmartQuotes::get(
            styles.get_ref(SmartQuoteElem::quotes),
            styles.get(TextElem::lang),
            styles.get(TextElem::region),
            styles.get(SmartQuoteElem::alternative),
        );
        let open = quotes.double_open;
        let close = quotes.double_close;
        eco_format!("{prefix} {open}{body}{close} {page_str} {page_nr}",)