summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Schmitz <tobiasschmitz2001@gmail.com>2025-07-08 14:14:37 +0200
committerTobias Schmitz <tobiasschmitz2001@gmail.com>2025-07-08 14:14:37 +0200
commitedd213074f476b283374c4e6bcb39ede5cf17e39 (patch)
tree04334253db5eb2d2ed01de0414a35391f694a026
parent070a0faf5c69b6a03b4b043b94bb4984367c1428 (diff)
refactor: remove general api to set cell kind and add pdf.(header|data)-cell
-rw-r--r--crates/typst-library/src/layout/grid/resolve.rs4
-rw-r--r--crates/typst-library/src/model/table.rs71
-rw-r--r--crates/typst-library/src/pdf/accessibility.rs74
-rw-r--r--crates/typst-library/src/pdf/mod.rs2
-rw-r--r--crates/typst-pdf/src/tags/mod.rs2
-rw-r--r--crates/typst-pdf/src/tags/table.rs9
6 files changed, 86 insertions, 76 deletions
diff --git a/crates/typst-library/src/layout/grid/resolve.rs b/crates/typst-library/src/layout/grid/resolve.rs
index 49f9e0ed..0724280b 100644
--- a/crates/typst-library/src/layout/grid/resolve.rs
+++ b/crates/typst-library/src/layout/grid/resolve.rs
@@ -22,7 +22,7 @@ use typst_syntax::Span;
use typst_utils::NonZeroExt;
use crate::introspection::SplitLocator;
-use crate::model::{TableCellKind, TableHeaderScope};
+use crate::pdf::{TableCellKind, TableHeaderScope};
/// Convert a grid to a cell grid.
#[typst_macros::time(span = elem.span())]
@@ -226,7 +226,7 @@ impl ResolvableCell for Packed<TableCell> {
let breakable = cell.breakable(styles).unwrap_or(breakable);
let fill = cell.fill(styles).unwrap_or_else(|| fill.clone());
- let kind = cell.kind(styles).or(kind);
+ let kind = cell.kind().copied().unwrap_or_default().or(kind);
let cell_stroke = cell.stroke(styles);
let stroke_overridden =
diff --git a/crates/typst-library/src/model/table.rs b/crates/typst-library/src/model/table.rs
index f8fe7691..7aacf07f 100644
--- a/crates/typst-library/src/model/table.rs
+++ b/crates/typst-library/src/model/table.rs
@@ -2,14 +2,13 @@ use std::num::{NonZeroU32, NonZeroUsize};
use std::sync::Arc;
use ecow::EcoString;
-use typst_macros::Cast;
use typst_utils::NonZeroExt;
use crate::diag::{bail, HintedStrResult, HintedString, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, dict, elem, scope, Content, Dict, NativeElement, Packed, Show, Smart,
- StyleChain, TargetElem,
+ cast, elem, scope, Content, NativeElement, Packed, Show, Smart, StyleChain,
+ TargetElem,
};
use crate::html::{attr, tag, HtmlAttrs, HtmlElem, HtmlTag};
use crate::introspection::{Locatable, Locator};
@@ -20,6 +19,7 @@ use crate::layout::{
TrackSizings,
};
use crate::model::Figurable;
+use crate::pdf::TableCellKind;
use crate::text::LocalName;
use crate::visualize::{Paint, Stroke};
@@ -811,7 +811,8 @@ pub struct TableCell {
#[fold]
pub stroke: Sides<Option<Option<Arc<Stroke>>>>,
- // TODO: feature gate
+ #[internal]
+ #[synthesized]
pub kind: Smart<TableCellKind>,
/// Whether rows spanned by this cell can be placed in different pages.
@@ -851,65 +852,3 @@ impl From<Content> for TableCell {
value.unpack::<Self>().unwrap_or_else(Self::new)
}
}
-
-#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum TableCellKind {
- Header(NonZeroU32, TableHeaderScope),
- Footer,
- #[default]
- Data,
-}
-
-cast! {
- TableCellKind,
- self => match self {
- Self::Header(level, scope) => dict! { "level" => level, "scope" => scope }.into_value(),
- Self::Footer => "footer".into_value(),
- Self::Data => "data".into_value(),
- },
- "header" => Self::Header(NonZeroU32::ONE, TableHeaderScope::default()),
- "footer" => Self::Footer,
- "data" => Self::Data,
- mut dict: Dict => {
- // TODO: have a `pdf.header` function instead?
- #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
- enum HeaderKind {
- Header,
- }
- dict.take("kind")?.cast::<HeaderKind>()?;
- let level = dict.take("level").ok().map(|v| v.cast()).transpose()?;
- let scope = dict.take("scope").ok().map(|v| v.cast()).transpose()?;
- dict.finish(&["kind", "level", "scope"])?;
- Self::Header(level.unwrap_or(NonZeroU32::ONE), scope.unwrap_or_default())
- },
-}
-
-/// The scope of a table header cell.
-#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Cast)]
-pub enum TableHeaderScope {
- /// The header cell refers to both the row and the column.
- Both,
- /// The header cell refers to the column.
- #[default]
- Column,
- /// The header cell refers to the row.
- Row,
-}
-
-impl TableHeaderScope {
- pub fn refers_to_column(&self) -> bool {
- match self {
- TableHeaderScope::Both => true,
- TableHeaderScope::Column => true,
- TableHeaderScope::Row => false,
- }
- }
-
- pub fn refers_to_row(&self) -> bool {
- match self {
- TableHeaderScope::Both => true,
- TableHeaderScope::Column => false,
- TableHeaderScope::Row => true,
- }
- }
-}
diff --git a/crates/typst-library/src/pdf/accessibility.rs b/crates/typst-library/src/pdf/accessibility.rs
index 7ec52f8c..9399c1c6 100644
--- a/crates/typst-library/src/pdf/accessibility.rs
+++ b/crates/typst-library/src/pdf/accessibility.rs
@@ -1,11 +1,14 @@
+use std::num::NonZeroU32;
+
use ecow::EcoString;
-use typst_macros::{cast, elem, Cast};
+use typst_macros::{cast, elem, func, Cast};
+use typst_utils::NonZeroExt;
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{Content, Packed, Show, StyleChain};
+use crate::foundations::{Content, NativeElement, Packed, Show, Smart, StyleChain};
use crate::introspection::Locatable;
-use crate::model::TableHeaderScope;
+use crate::model::TableCell;
// TODO: docs
#[elem(Locatable, Show)]
@@ -210,3 +213,68 @@ impl Show for Packed<ArtifactElem> {
Ok(self.body.clone())
}
}
+
+// TODO: feature gate
+/// Explicity define this cell as a header cell.
+#[func]
+pub fn header_cell(
+ #[named]
+ #[default(NonZeroU32::ONE)]
+ level: NonZeroU32,
+ #[named]
+ #[default]
+ scope: TableHeaderScope,
+ /// The table cell.
+ cell: TableCell,
+) -> Content {
+ cell.with_kind(Smart::Custom(TableCellKind::Header(level, scope)))
+ .pack()
+}
+
+// TODO: feature gate
+/// Explicity define this cell as a data cell.
+#[func]
+pub fn data_cell(
+ /// The table cell.
+ cell: TableCell,
+) -> Content {
+ cell.with_kind(Smart::Custom(TableCellKind::Data)).pack()
+}
+
+#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
+pub enum TableCellKind {
+ Header(NonZeroU32, TableHeaderScope),
+ Footer,
+ #[default]
+ Data,
+}
+
+/// The scope of a table header cell.
+#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Cast)]
+pub enum TableHeaderScope {
+ /// The header cell refers to both the row and the column.
+ Both,
+ /// The header cell refers to the column.
+ #[default]
+ Column,
+ /// The header cell refers to the row.
+ Row,
+}
+
+impl TableHeaderScope {
+ pub fn refers_to_column(&self) -> bool {
+ match self {
+ TableHeaderScope::Both => true,
+ TableHeaderScope::Column => true,
+ TableHeaderScope::Row => false,
+ }
+ }
+
+ pub fn refers_to_row(&self) -> bool {
+ match self {
+ TableHeaderScope::Both => true,
+ TableHeaderScope::Column => false,
+ TableHeaderScope::Row => true,
+ }
+ }
+}
diff --git a/crates/typst-library/src/pdf/mod.rs b/crates/typst-library/src/pdf/mod.rs
index 952e7fe3..8a0d40b9 100644
--- a/crates/typst-library/src/pdf/mod.rs
+++ b/crates/typst-library/src/pdf/mod.rs
@@ -15,5 +15,7 @@ pub fn module() -> Module {
pdf.define_elem::<EmbedElem>();
pdf.define_elem::<PdfTagElem>();
pdf.define_elem::<ArtifactElem>();
+ pdf.define_func::<header_cell>();
+ pdf.define_func::<data_cell>();
Module::new("pdf", pdf)
}
diff --git a/crates/typst-pdf/src/tags/mod.rs b/crates/typst-pdf/src/tags/mod.rs
index 5aa4d390..fd9e9394 100644
--- a/crates/typst-pdf/src/tags/mod.rs
+++ b/crates/typst-pdf/src/tags/mod.rs
@@ -181,7 +181,7 @@ pub(crate) fn handle_end(gc: &mut GlobalContext, loc: Location) {
return;
};
- table_ctx.insert(cell, entry.nodes);
+ table_ctx.insert(&cell, entry.nodes);
return;
}
StackEntryKind::Link(_, link) => {
diff --git a/crates/typst-pdf/src/tags/table.rs b/crates/typst-pdf/src/tags/table.rs
index 177de962..fc3ab8a5 100644
--- a/crates/typst-pdf/src/tags/table.rs
+++ b/crates/typst-pdf/src/tags/table.rs
@@ -7,7 +7,8 @@ use krilla::tagging::{
};
use smallvec::SmallVec;
use typst_library::foundations::{Packed, Smart, StyleChain};
-use typst_library::model::{TableCell, TableCellKind, TableHeaderScope};
+use typst_library::model::TableCell;
+use typst_library::pdf::{TableCellKind, TableHeaderScope};
use crate::tags::{TableId, TagNode};
@@ -54,12 +55,12 @@ impl TableCtx {
}
}
- pub(crate) fn insert(&mut self, cell: Packed<TableCell>, nodes: Vec<TagNode>) {
+ pub(crate) fn insert(&mut self, cell: &TableCell, nodes: Vec<TagNode>) {
let x = cell.x(StyleChain::default()).unwrap_or_else(|| unreachable!());
let y = cell.y(StyleChain::default()).unwrap_or_else(|| unreachable!());
let rowspan = cell.rowspan(StyleChain::default());
let colspan = cell.colspan(StyleChain::default());
- let kind = cell.kind(StyleChain::default());
+ let kind = cell.kind().copied().expect("kind to be set after layouting");
// Extend the table grid to fit this cell.
let required_height = y + rowspan.get();
@@ -344,7 +345,7 @@ mod tests {
fn table<const SIZE: usize>(cells: [TableCell; SIZE]) -> TableCtx {
let mut table = TableCtx::new(TableId(324), Some("summary".into()));
for cell in cells {
- table.insert(Packed::new(cell), Vec::new());
+ table.insert(&cell, Vec::new());
}
table
}