feat: mark all shapes as artifacts

This commit is contained in:
Tobias Schmitz 2025-07-12 20:02:28 +02:00
parent e3c0855a2b
commit a495724813
No known key found for this signature in database
2 changed files with 52 additions and 36 deletions

View File

@ -1,6 +1,7 @@
use krilla::geom::{Path, PathBuilder, Rect}; use krilla::geom::{Path, PathBuilder, Rect};
use krilla::surface::Surface; use krilla::surface::Surface;
use typst_library::diag::SourceResult; use typst_library::diag::SourceResult;
use typst_library::pdf::ArtifactKind;
use typst_library::visualize::{Geometry, Shape}; use typst_library::visualize::{Geometry, Shape};
use typst_syntax::Span; use typst_syntax::Span;
@ -16,7 +17,7 @@ pub(crate) fn handle_shape(
gc: &mut GlobalContext, gc: &mut GlobalContext,
span: Span, span: Span,
) -> SourceResult<()> { ) -> SourceResult<()> {
let mut handle = tags::start_marked(gc, surface); let mut handle = tags::start_artifact(gc, surface, ArtifactKind::Other);
let surface = handle.surface(); let surface = handle.surface();
surface.set_location(span.into_raw().get()); surface.set_location(span.into_raw().get());

View File

@ -45,10 +45,10 @@ pub(crate) fn handle_start(
if let Some(artifact) = elem.to_packed::<ArtifactElem>() { if let Some(artifact) = elem.to_packed::<ArtifactElem>() {
let kind = artifact.kind.get(StyleChain::default()); let kind = artifact.kind.get(StyleChain::default());
start_artifact(gc, surface, loc, kind); push_artifact(gc, surface, loc, kind);
return Ok(()); return Ok(());
} else if let Some(_) = elem.to_packed::<RepeatElem>() { } else if let Some(_) = elem.to_packed::<RepeatElem>() {
start_artifact(gc, surface, loc, ArtifactKind::Other); push_artifact(gc, surface, loc, ArtifactKind::Other);
return Ok(()); return Ok(());
} }
@ -107,7 +107,7 @@ pub(crate) fn handle_start(
// first page. Maybe it should be the cell on the last page, but that // first page. Maybe it should be the cell on the last page, but that
// would require more changes in the layouting code, or a pre-pass // would require more changes in the layouting code, or a pre-pass
// on the frames to figure out if there are other footers following. // on the frames to figure out if there are other footers following.
start_artifact(gc, surface, loc, ArtifactKind::Other); push_artifact(gc, surface, loc, ArtifactKind::Other);
} else { } else {
push_stack(gc, loc, StackEntryKind::TableCell(cell.clone()))?; push_stack(gc, loc, StackEntryKind::TableCell(cell.clone()))?;
} }
@ -125,29 +125,10 @@ pub(crate) fn handle_start(
Ok(()) Ok(())
} }
fn push_stack(
gc: &mut GlobalContext,
loc: Location,
kind: StackEntryKind,
) -> SourceResult<()> {
if !gc.tags.context_supports(&kind) {
if gc.options.standards.config.validator() == Validator::UA1 {
// TODO: error
} else {
// TODO: warning
}
}
gc.tags.stack.push(StackEntry { loc, kind, nodes: Vec::new() });
Ok(())
}
pub(crate) fn handle_end(gc: &mut GlobalContext, surface: &mut Surface, loc: Location) { pub(crate) fn handle_end(gc: &mut GlobalContext, surface: &mut Surface, loc: Location) {
if let Some((l, _)) = gc.tags.in_artifact { if let Some((l, _)) = gc.tags.in_artifact {
if l == loc { if l == loc {
surface.end_tagged(); pop_artifact(gc, surface);
gc.tags.in_artifact = None;
} }
return; return;
} }
@ -205,6 +186,41 @@ pub(crate) fn handle_end(gc: &mut GlobalContext, surface: &mut Surface, loc: Loc
gc.tags.push(node); gc.tags.push(node);
} }
fn push_stack(
gc: &mut GlobalContext,
loc: Location,
kind: StackEntryKind,
) -> SourceResult<()> {
if !gc.tags.context_supports(&kind) {
if gc.options.standards.config.validator() == Validator::UA1 {
// TODO: error
} else {
// TODO: warning
}
}
gc.tags.stack.push(StackEntry { loc, kind, nodes: Vec::new() });
Ok(())
}
fn push_artifact(
gc: &mut GlobalContext,
surface: &mut Surface,
loc: Location,
kind: ArtifactKind,
) {
let ty = artifact_type(kind);
let id = surface.start_tagged(ContentTag::Artifact(ty));
gc.tags.push(TagNode::Leaf(id));
gc.tags.in_artifact = Some((loc, kind));
}
fn pop_artifact(gc: &mut GlobalContext, surface: &mut Surface) {
surface.end_tagged();
gc.tags.in_artifact = None;
}
pub(crate) fn page_start(gc: &mut GlobalContext, surface: &mut Surface) { pub(crate) fn page_start(gc: &mut GlobalContext, surface: &mut Surface) {
if let Some((_, kind)) = gc.tags.in_artifact { if let Some((_, kind)) = gc.tags.in_artifact {
let ty = artifact_type(kind); let ty = artifact_type(kind);
@ -452,6 +468,17 @@ pub(crate) fn start_span<'a, 'b>(
start_content(gc, surface, ContentTag::Span(span)) start_content(gc, surface, ContentTag::Span(span))
} }
/// Returns a [`TagHandle`] that automatically calls [`Surface::end_tagged`]
/// when dropped.
pub(crate) fn start_artifact<'a, 'b>(
gc: &mut GlobalContext,
surface: &'b mut Surface<'a>,
kind: ArtifactKind,
) -> TagHandle<'a, 'b> {
let ty = artifact_type(kind);
start_content(gc, surface, ContentTag::Artifact(ty))
}
fn start_content<'a, 'b>( fn start_content<'a, 'b>(
gc: &mut GlobalContext, gc: &mut GlobalContext,
surface: &'b mut Surface<'a>, surface: &'b mut Surface<'a>,
@ -471,18 +498,6 @@ fn start_content<'a, 'b>(
TagHandle { surface, started: true } TagHandle { surface, started: true }
} }
fn start_artifact(
gc: &mut GlobalContext,
surface: &mut Surface,
loc: Location,
kind: ArtifactKind,
) {
let ty = artifact_type(kind);
let id = surface.start_tagged(ContentTag::Artifact(ty));
gc.tags.push(TagNode::Leaf(id));
gc.tags.in_artifact = Some((loc, kind));
}
fn artifact_type(kind: ArtifactKind) -> ArtifactType { fn artifact_type(kind: ArtifactKind) -> ArtifactType {
match kind { match kind {
ArtifactKind::Header => ArtifactType::Header, ArtifactKind::Header => ArtifactType::Header,