From 4a64a717e8ff19d4be1dc97ab37bf6e4f1ab8db5 Mon Sep 17 00:00:00 2001 From: Tobias Schmitz Date: Tue, 17 Jun 2025 17:00:33 +0200 Subject: [PATCH] WIP [no ci] --- crates/typst-library/src/model/outline.rs | 1 + crates/typst-pdf/src/link.rs | 8 ++--- crates/typst-pdf/src/tags.rs | 36 +++++++++-------------- 3 files changed, 19 insertions(+), 26 deletions(-) diff --git a/crates/typst-library/src/model/outline.rs b/crates/typst-library/src/model/outline.rs index 746a8ae06..a13e0c859 100644 --- a/crates/typst-library/src/model/outline.rs +++ b/crates/typst-library/src/model/outline.rs @@ -422,6 +422,7 @@ impl Show for Packed { let context = Context::new(None, Some(styles)); let context = context.track(); + // TODO: prefix should be wrapped in a `Lbl` structure element let prefix = self.prefix(engine, context, span)?; let body = self.body().at(span)?; let page = self.page(engine, context, span)?; diff --git a/crates/typst-pdf/src/link.rs b/crates/typst-pdf/src/link.rs index c78ca389f..1fe2c701a 100644 --- a/crates/typst-pdf/src/link.rs +++ b/crates/typst-pdf/src/link.rs @@ -74,12 +74,12 @@ pub(crate) fn handle_link( let placeholder = gc.tags.reserve_placeholder(); let mut node = TagNode::Placeholder(placeholder); - let (parent_tag, _) = gc.tags.parent_nodes(); - if !matches!(parent_tag, Some(Tag::Link | Tag::Reference)) { - node = TagNode::Group(Link, ) + let (parent_tag, _) = gc.tags.parent(); + if !matches!(parent_tag, Some(Tag::Link)) { + node = TagNode::Group(Tag::Link, vec![node]); } // Prepend so the link annotation is the first child. - gc.tags.prepend(); + gc.tags.prepend(node); fc.push_annotation( placeholder, diff --git a/crates/typst-pdf/src/tags.rs b/crates/typst-pdf/src/tags.rs index 1c5b0bef0..780a88418 100644 --- a/crates/typst-pdf/src/tags.rs +++ b/crates/typst-pdf/src/tags.rs @@ -67,20 +67,22 @@ impl Tags { .expect("initialized placeholder node") } - pub(crate) fn push(&mut self, node: TagNode) { - if let Some((_, _, nodes)) = self.stack.last_mut() { - nodes.push(node); + /// Returns the current parent's list of children and the structure type ([Tag]). + /// In case of the document root the structure type will be `None`. + pub(crate) fn parent(&mut self) -> (Option<&mut Tag>, &mut Vec) { + if let Some((_, tag, parent_nodes)) = self.stack.last_mut() { + (Some(tag), parent_nodes) } else { - self.tree.push(node); + (None, &mut self.tree) } } + pub(crate) fn push(&mut self, node: TagNode) { + self.parent().1.push(node); + } + pub(crate) fn prepend(&mut self, node: TagNode) { - if let Some((_, _, nodes)) = self.stack.last_mut() { - nodes.insert(0, node); - } else { - self.tree.insert(0, node); - } + self.parent().1.insert(0, node); } pub(crate) fn build_tree(&mut self) -> TagTree { @@ -109,15 +111,6 @@ impl Tags { } } - /// Returns the current parent's list of children and whether it is the tree root. - pub(crate) fn parent_nodes(&mut self) -> (Option<&mut Tag>, &mut Vec) { - if let Some((_, tag, parent_nodes)) = self.stack.last_mut() { - (Some(tag), parent_nodes) - } else { - (None, &mut self.tree) - } - } - fn context_supports(&self, _tag: &Tag) -> bool { // TODO: generate using: https://pdfa.org/resource/iso-ts-32005-hierarchical-inclusion-rules/ true @@ -245,9 +238,9 @@ pub(crate) fn handle_end(gc: &mut GlobalContext, surface: &mut Surface, loc: &Lo surface.end_tagged(); - let (is_root, parent_nodes) = gc.tags.parent_nodes(); + let (parent_tag, parent_nodes) = gc.tags.parent(); parent_nodes.push(TagNode::Group(tag, nodes)); - if !is_root { + if parent_tag.is_some() { // TODO: somehow avoid empty marked-content sequences let id = surface.start_tagged(ContentTag::Other); parent_nodes.push(TagNode::Leaf(id)); @@ -258,8 +251,7 @@ fn start_artifact(gc: &mut GlobalContext, surface: &mut Surface, kind: ArtifactK let ty = artifact_type(kind); let id = surface.start_tagged(ContentTag::Artifact(ty)); - let (_, parent_nodes) = gc.tags.parent_nodes(); - parent_nodes.push(TagNode::Leaf(id)); + gc.tags.push(TagNode::Leaf(id)); } fn artifact_type(kind: ArtifactKind) -> ArtifactType {