From 50a280b6c2c8fdb482bfd81093aac5ee1f294705 Mon Sep 17 00:00:00 2001 From: Tobias Schmitz Date: Thu, 24 Jul 2025 18:03:10 +0200 Subject: [PATCH] feat: avoid doing extra work when `--disable-pdf-tags` is passed --- crates/typst-pdf/src/convert.rs | 2 +- crates/typst-pdf/src/link.rs | 21 ++++++++++++------ crates/typst-pdf/src/tags/mod.rs | 37 ++++++++++++++++++++++++++------ 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/crates/typst-pdf/src/convert.rs b/crates/typst-pdf/src/convert.rs index e9a8d3186..ca55eacb7 100644 --- a/crates/typst-pdf/src/convert.rs +++ b/crates/typst-pdf/src/convert.rs @@ -124,7 +124,7 @@ fn convert_pages(gc: &mut GlobalContext, document: &mut Document) -> SourceResul surface.finish(); - tags::add_annotations(gc, &mut page, fc.link_annotations); + tags::add_link_annotations(gc, &mut page, fc.link_annotations); } } diff --git a/crates/typst-pdf/src/link.rs b/crates/typst-pdf/src/link.rs index df1e926de..b8e5e98a3 100644 --- a/crates/typst-pdf/src/link.rs +++ b/crates/typst-pdf/src/link.rs @@ -50,11 +50,14 @@ pub(crate) fn handle_link( } }; - let Some((link_id, link, link_nodes)) = gc.tags.stack.find_parent_link() else { - unreachable!("expected a link parent") + let (link_id, tagging_ctx) = match gc.tags.stack.find_parent_link() { + Some((link_id, link, nodes)) => (link_id, Some((link, nodes))), + None if gc.options.disable_tags => { + let link_id = gc.tags.next_link_id(); + (link_id, None) + } + None => unreachable!("expected a link parent"), }; - let alt = link.alt.as_ref().map(EcoString::to_string); - let quad = to_quadrilateral(fc, size); // Unfortunately quadpoints still aren't well supported by most PDF readers, @@ -65,14 +68,20 @@ pub(crate) fn handle_link( Some(annotation) if should_use_quadpoints => annotation.quad_points.push(quad), _ => { let placeholder = gc.tags.placeholders.reserve(); - link_nodes.push(TagNode::Placeholder(placeholder)); + let (alt, span) = if let Some((link, nodes)) = tagging_ctx { + nodes.push(TagNode::Placeholder(placeholder)); + let alt = link.alt.as_ref().map(EcoString::to_string); + (alt, link.span) + } else { + (None, Span::detached()) + }; fc.push_link_annotation(LinkAnnotation { id: link_id, placeholder, quad_points: vec![quad], alt, target, - span: link.span, + span, }); } } diff --git a/crates/typst-pdf/src/tags/mod.rs b/crates/typst-pdf/src/tags/mod.rs index 052cb7083..426530834 100644 --- a/crates/typst-pdf/src/tags/mod.rs +++ b/crates/typst-pdf/src/tags/mod.rs @@ -43,6 +43,10 @@ pub(crate) fn handle_start( surface: &mut Surface, elem: &Content, ) -> SourceResult<()> { + if gc.options.disable_tags { + return Ok(()); + } + if gc.tags.in_artifact.is_some() { // Don't nest artifacts return Ok(()); @@ -187,6 +191,10 @@ pub(crate) fn handle_start( } pub(crate) fn handle_end(gc: &mut GlobalContext, surface: &mut Surface, loc: Location) { + if gc.options.disable_tags { + return; + } + if let Some((l, _)) = gc.tags.in_artifact { if l == loc { pop_artifact(gc, surface); @@ -316,6 +324,10 @@ fn pop_artifact(gc: &mut GlobalContext, surface: &mut Surface) { } pub(crate) fn page_start(gc: &mut GlobalContext, surface: &mut Surface) { + if gc.options.disable_tags { + return; + } + if let Some((_, kind)) = gc.tags.in_artifact { let ty = artifact_type(kind); let id = surface.start_tagged(ContentTag::Artifact(ty)); @@ -324,13 +336,17 @@ pub(crate) fn page_start(gc: &mut GlobalContext, surface: &mut Surface) { } pub(crate) fn page_end(gc: &mut GlobalContext, surface: &mut Surface) { + if gc.options.disable_tags { + return; + } + if gc.tags.in_artifact.is_some() { surface.end_tagged(); } } /// Add all annotations that were found in the page frame. -pub(crate) fn add_annotations( +pub(crate) fn add_link_annotations( gc: &mut GlobalContext, page: &mut Page, annotations: Vec, @@ -343,8 +359,13 @@ pub(crate) fn add_annotations( alt, ) .with_location(Some(span.into_raw().get())); - let annot_id = page.add_tagged_annotation(annot); - gc.tags.placeholders.init(placeholder, Node::Leaf(annot_id)); + + if gc.options.disable_tags { + page.add_annotation(annot); + } else { + let annot_id = page.add_tagged_annotation(annot); + gc.tags.placeholders.init(placeholder, Node::Leaf(annot_id)); + } } } @@ -372,10 +393,10 @@ pub(crate) struct Tags { pub(crate) footnotes: HashMap, pub(crate) in_artifact: Option<(Location, ArtifactKind)>, /// Used to group multiple link annotations using quad points. - pub(crate) link_id: LinkId, + link_id: LinkId, /// Used to generate IDs referenced in table `Headers` attributes. /// The IDs must be document wide unique. - pub(crate) table_id: TableId, + table_id: TableId, /// The output. pub(crate) tree: Vec, @@ -444,7 +465,7 @@ impl Tags { true } - fn next_link_id(&mut self) -> LinkId { + pub(crate) fn next_link_id(&mut self) -> LinkId { self.link_id.0 += 1; self.link_id } @@ -770,6 +791,10 @@ fn start_content<'a, 'b>( surface: &'b mut Surface<'a>, content: ContentTag, ) -> TagHandle<'a, 'b> { + if gc.options.disable_tags { + return TagHandle { surface, started: false }; + } + let content = if gc.tags.in_artifact.is_some() { return TagHandle { surface, started: false }; } else if let Some(StackEntryKind::Table(_)) = gc.tags.stack.last().map(|e| &e.kind) {