mirror of
https://github.com/typst/typst
synced 2025-08-06 11:17:54 +08:00
fix: ignore any tags inside of tilings
This commit is contained in:
parent
b312b45b19
commit
7ea16f25b5
@ -16,6 +16,7 @@ use typst_library::visualize::{
|
||||
use typst_utils::Numeric;
|
||||
|
||||
use crate::convert::{FrameContext, GlobalContext, State, handle_frame};
|
||||
use crate::tags::{self, Disable};
|
||||
use crate::util::{AbsExt, FillRuleExt, LineCapExt, LineJoinExt, TransformExt};
|
||||
|
||||
pub(crate) fn convert_fill(
|
||||
@ -127,8 +128,12 @@ fn convert_pattern(
|
||||
|
||||
let mut stream_builder = surface.stream_builder();
|
||||
let mut surface = stream_builder.surface();
|
||||
let mut fc = FrameContext::new(None, pattern.frame().size());
|
||||
handle_frame(&mut fc, pattern.frame(), None, &mut surface, gc)?;
|
||||
{
|
||||
let mut handle = tags::disable(gc, &mut surface, Disable::Tiling);
|
||||
let (gc, surface) = handle.reborrow();
|
||||
let mut fc = FrameContext::new(None, pattern.frame().size());
|
||||
handle_frame(&mut fc, pattern.frame(), None, surface, gc)?;
|
||||
}
|
||||
surface.finish();
|
||||
let stream = stream_builder.finish();
|
||||
let pattern = Pattern {
|
||||
|
@ -38,7 +38,7 @@ pub struct Tags {
|
||||
/// before the reference in the text, so we only resolve them once tags
|
||||
/// for the whole document are generated.
|
||||
pub footnotes: HashMap<Location, FootnoteCtx>,
|
||||
pub in_artifact: Option<(Location, ArtifactKind)>,
|
||||
pub disable: Option<Disable>,
|
||||
/// Used to group multiple link annotations using quad points.
|
||||
link_id: LinkId,
|
||||
/// Used to generate IDs referenced in table `Headers` attributes.
|
||||
@ -57,7 +57,7 @@ impl Tags {
|
||||
stack: TagStack::new(),
|
||||
placeholders: Placeholders(Vec::new()),
|
||||
footnotes: HashMap::new(),
|
||||
in_artifact: None,
|
||||
disable: None,
|
||||
|
||||
link_id: LinkId(0),
|
||||
table_id: TableId(0),
|
||||
@ -187,6 +187,12 @@ impl Tags {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Disable {
|
||||
ArtifactTag(Location, ArtifactKind),
|
||||
Tiling,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TextAttrs {
|
||||
lineheight: Option<LineHeight>,
|
||||
|
@ -100,17 +100,17 @@ pub fn handle_start(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if gc.tags.in_artifact.is_some() {
|
||||
if gc.tags.disable.is_some() {
|
||||
// Don't nest artifacts
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(artifact) = elem.to_packed::<ArtifactElem>() {
|
||||
let kind = artifact.kind.val();
|
||||
push_artifact(gc, surface, elem, kind);
|
||||
push_artifact_tag(gc, surface, elem, kind);
|
||||
return Ok(());
|
||||
} else if let Some(_) = elem.to_packed::<RepeatElem>() {
|
||||
push_artifact(gc, surface, elem, ArtifactKind::Other);
|
||||
push_artifact_tag(gc, surface, elem, ArtifactKind::Other);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -207,7 +207,7 @@ pub fn handle_start(
|
||||
// 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
|
||||
// on the frames to figure out if there are other footers following.
|
||||
push_artifact(gc, surface, elem, ArtifactKind::Other);
|
||||
push_artifact_tag(gc, surface, elem, ArtifactKind::Other);
|
||||
} else {
|
||||
push_stack(gc, elem, StackEntryKind::TableCell(cell.clone()))?;
|
||||
}
|
||||
@ -312,7 +312,7 @@ fn push_stack(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn push_artifact(
|
||||
fn push_artifact_tag(
|
||||
gc: &mut GlobalContext,
|
||||
surface: &mut Surface,
|
||||
elem: &Content,
|
||||
@ -321,7 +321,7 @@ fn push_artifact(
|
||||
let loc = elem.location().expect("elem to be locatable");
|
||||
let ty = artifact_type(kind);
|
||||
surface.start_tagged(ContentTag::Artifact(ty));
|
||||
gc.tags.in_artifact = Some((loc, kind));
|
||||
gc.tags.disable = Some(Disable::ArtifactTag(loc, kind));
|
||||
}
|
||||
|
||||
pub fn handle_end(
|
||||
@ -333,10 +333,11 @@ pub fn handle_end(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some((l, _)) = gc.tags.in_artifact
|
||||
if let Some(Disable::ArtifactTag(l, _)) = gc.tags.disable
|
||||
&& l == loc
|
||||
{
|
||||
pop_artifact(gc, surface);
|
||||
surface.end_tagged();
|
||||
gc.tags.disable = None;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -533,17 +534,16 @@ fn pop_stack(gc: &mut GlobalContext, entry: StackEntry) {
|
||||
gc.tags.push(node);
|
||||
}
|
||||
|
||||
fn pop_artifact(gc: &mut GlobalContext, surface: &mut Surface) {
|
||||
surface.end_tagged();
|
||||
gc.tags.in_artifact = None;
|
||||
}
|
||||
|
||||
pub fn page_start(gc: &mut GlobalContext, surface: &mut Surface) {
|
||||
if gc.options.disable_tags {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some((_, kind)) = gc.tags.in_artifact {
|
||||
if let Some(disable) = gc.tags.disable {
|
||||
let kind = match disable {
|
||||
Disable::ArtifactTag(_, kind) => kind,
|
||||
Disable::Tiling => ArtifactKind::Other,
|
||||
};
|
||||
let ty = artifact_type(kind);
|
||||
surface.start_tagged(ContentTag::Artifact(ty));
|
||||
}
|
||||
@ -554,7 +554,7 @@ pub fn page_end(gc: &mut GlobalContext, surface: &mut Surface) {
|
||||
return;
|
||||
}
|
||||
|
||||
if gc.tags.in_artifact.is_some() {
|
||||
if gc.tags.disable.is_some() {
|
||||
surface.end_tagged();
|
||||
}
|
||||
}
|
||||
@ -584,6 +584,43 @@ pub fn add_link_annotations(
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DisableHandle<'a, 'b, 'c, 'd> {
|
||||
gc: &'b mut GlobalContext<'a>,
|
||||
surface: &'d mut Surface<'c>,
|
||||
/// Whether this handle started the disabled range.
|
||||
started: bool,
|
||||
}
|
||||
|
||||
impl Drop for DisableHandle<'_, '_, '_, '_> {
|
||||
fn drop(&mut self) {
|
||||
if self.started {
|
||||
self.gc.tags.disable = None;
|
||||
self.surface.end_tagged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'c> DisableHandle<'a, '_, 'c, '_> {
|
||||
pub fn reborrow<'s>(
|
||||
&'s mut self,
|
||||
) -> (&'s mut GlobalContext<'a>, &'s mut Surface<'c>) {
|
||||
(self.gc, self.surface)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disable<'a, 'b, 'c, 'd>(
|
||||
gc: &'b mut GlobalContext<'a>,
|
||||
surface: &'d mut Surface<'c>,
|
||||
kind: Disable,
|
||||
) -> DisableHandle<'a, 'b, 'c, 'd> {
|
||||
let started = gc.tags.disable.is_none();
|
||||
if started {
|
||||
gc.tags.disable = Some(kind);
|
||||
surface.start_tagged(ContentTag::Artifact(ArtifactType::Other));
|
||||
}
|
||||
DisableHandle { gc, surface, started }
|
||||
}
|
||||
|
||||
pub fn text<'a, 'b>(
|
||||
gc: &mut GlobalContext,
|
||||
fc: &FrameContext,
|
||||
@ -596,7 +633,7 @@ pub fn text<'a, 'b>(
|
||||
|
||||
update_bbox(gc, fc, || text.bbox());
|
||||
|
||||
if gc.tags.in_artifact.is_some() {
|
||||
if gc.tags.disable.is_some() {
|
||||
return TagHandle { surface, started: false };
|
||||
}
|
||||
|
||||
@ -682,25 +719,16 @@ fn start_content<'a, 'b>(
|
||||
surface: &'b mut Surface<'a>,
|
||||
content: ContentTag,
|
||||
) -> TagHandle<'a, 'b> {
|
||||
if gc.tags.in_artifact.is_some() {
|
||||
if gc.tags.disable.is_some() {
|
||||
return TagHandle { surface, started: false };
|
||||
} else if let Some(StackEntryKind::Table(_)) = gc.tags.stack.last().map(|e| &e.kind) {
|
||||
// TODO: handle this more like other artifacts
|
||||
// Mark any direct child of a table as an aritfact. Any real content
|
||||
// will be wrapped inside a `TableCell`.
|
||||
|
||||
// Don't store artifact content ids, they will be omitted anyway when
|
||||
// serializing the tag tree.
|
||||
surface.start_tagged(ContentTag::Artifact(ArtifactType::Other));
|
||||
TagHandle { surface, started: true }
|
||||
} else {
|
||||
let artifact = matches!(content, ContentTag::Artifact(_));
|
||||
let id = surface.start_tagged(content);
|
||||
if !artifact {
|
||||
gc.tags.push(TagNode::Leaf(id));
|
||||
}
|
||||
TagHandle { surface, started: true }
|
||||
}
|
||||
|
||||
let artifact = matches!(content, ContentTag::Artifact(_));
|
||||
let id = surface.start_tagged(content);
|
||||
if !artifact {
|
||||
gc.tags.push(TagNode::Leaf(id));
|
||||
}
|
||||
TagHandle { surface, started: true }
|
||||
}
|
||||
|
||||
fn artifact_type(kind: ArtifactKind) -> ArtifactType {
|
||||
|
8
tests/ref/pdftags/disable-tags-artifact.yml
Normal file
8
tests/ref/pdftags/disable-tags-artifact.yml
Normal file
@ -0,0 +1,8 @@
|
||||
- Tag: H1
|
||||
/T: "Heading 1"
|
||||
/K:
|
||||
- Content: page=0 mcid=0
|
||||
- Tag: H1
|
||||
/T: "Heading 2"
|
||||
/K:
|
||||
- Content: page=0 mcid=1
|
4
tests/ref/pdftags/disable-tags-tiling.yml
Normal file
4
tests/ref/pdftags/disable-tags-tiling.yml
Normal file
@ -0,0 +1,4 @@
|
||||
- Tag: H1
|
||||
/T: "Rectangle"
|
||||
/K:
|
||||
- Content: page=0 mcid=0
|
21
tests/suite/pdftags/disable.typ
Normal file
21
tests/suite/pdftags/disable.typ
Normal file
@ -0,0 +1,21 @@
|
||||
--- disable-tags-artifact pdftags ---
|
||||
= Heading 1
|
||||
#pdf.artifact[
|
||||
#table(
|
||||
columns: 2,
|
||||
[a], [b],
|
||||
[c], [d],
|
||||
)
|
||||
]
|
||||
|
||||
= Heading 2
|
||||
|
||||
--- disable-tags-tiling pdftags ---
|
||||
= Rectangle
|
||||
|
||||
#let pat = tiling(size: (20pt, 20pt))[
|
||||
- a
|
||||
- b
|
||||
- c
|
||||
]
|
||||
#rect(fill: pat)
|
Loading…
x
Reference in New Issue
Block a user