mirror of
https://github.com/typst/typst
synced 2025-08-18 00:48:34 +08:00
Compare commits
4 Commits
2621c6416e
...
4b57373653
Author | SHA1 | Date | |
---|---|---|---|
|
4b57373653 | ||
|
e43b8bbb7f | ||
|
9bbfe4c14a | ||
|
e4021390a3 |
@ -294,7 +294,7 @@ const HEADING_RULE: ShowFn<HeadingElem> = |elem, engine, styles| {
|
|||||||
|
|
||||||
const FIGURE_RULE: ShowFn<FigureElem> = |elem, _, styles| {
|
const FIGURE_RULE: ShowFn<FigureElem> = |elem, _, styles| {
|
||||||
let span = elem.span();
|
let span = elem.span();
|
||||||
let mut realized = elem.body.clone();
|
let mut realized = PdfMarkerTag::FigureBody(elem.body.clone());
|
||||||
|
|
||||||
// Build the caption, if any.
|
// Build the caption, if any.
|
||||||
if let Some(caption) = elem.caption.get_cloned(styles) {
|
if let Some(caption) = elem.caption.get_cloned(styles) {
|
||||||
|
@ -132,6 +132,8 @@ macro_rules! pdf_marker_tag {
|
|||||||
pdf_marker_tag! {
|
pdf_marker_tag! {
|
||||||
/// `TOC`
|
/// `TOC`
|
||||||
OutlineBody,
|
OutlineBody,
|
||||||
|
/// `Figure`
|
||||||
|
FigureBody,
|
||||||
/// `Lbl` (marker) of the list item
|
/// `Lbl` (marker) of the list item
|
||||||
ListItemLabel,
|
ListItemLabel,
|
||||||
/// `LBody` of the enum item
|
/// `LBody` of the enum item
|
||||||
|
@ -2,11 +2,13 @@ use krilla::tagging::{ListNumbering, TagKind};
|
|||||||
|
|
||||||
use crate::tags::TagNode;
|
use crate::tags::TagNode;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct ListCtx {
|
pub(crate) struct ListCtx {
|
||||||
numbering: ListNumbering,
|
numbering: ListNumbering,
|
||||||
items: Vec<ListItem>,
|
items: Vec<ListItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct ListItem {
|
struct ListItem {
|
||||||
label: Vec<TagNode>,
|
label: Vec<TagNode>,
|
||||||
body: Option<Vec<TagNode>>,
|
body: Option<Vec<TagNode>>,
|
||||||
|
@ -60,6 +60,7 @@ pub(crate) fn handle_start(
|
|||||||
push_stack(gc, loc, StackEntryKind::Outline(OutlineCtx::new()))?;
|
push_stack(gc, loc, StackEntryKind::Outline(OutlineCtx::new()))?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
PdfMarkerTagKind::FigureBody => TagKind::Figure.into(),
|
||||||
PdfMarkerTagKind::ListItemLabel => {
|
PdfMarkerTagKind::ListItemLabel => {
|
||||||
push_stack(gc, loc, StackEntryKind::ListItemLabel)?;
|
push_stack(gc, loc, StackEntryKind::ListItemLabel)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -81,8 +82,13 @@ pub(crate) fn handle_start(
|
|||||||
push_stack(gc, loc, StackEntryKind::List(ListCtx::new(numbering)))?;
|
push_stack(gc, loc, StackEntryKind::List(ListCtx::new(numbering)))?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else if let Some(_) = elem.to_packed::<FigureElem>() {
|
} else if let Some(_) = elem.to_packed::<FigureElem>() {
|
||||||
let alt = None; // TODO
|
// Wrap the figure tag and the sibling caption in a container, if the
|
||||||
TagKind::Figure.with_alt_text(alt)
|
// caption is contained within the figure like recommended for tables
|
||||||
|
// screen readers might ignore it.
|
||||||
|
// TODO: maybe this could be a `NonStruct` tag?
|
||||||
|
TagKind::P.into()
|
||||||
|
} else if let Some(_) = elem.to_packed::<FigureCaption>() {
|
||||||
|
TagKind::Caption.into()
|
||||||
} else if let Some(image) = elem.to_packed::<ImageElem>() {
|
} else if let Some(image) = elem.to_packed::<ImageElem>() {
|
||||||
let alt = image.alt.get_as_ref().map(|s| s.to_string());
|
let alt = image.alt.get_as_ref().map(|s| s.to_string());
|
||||||
|
|
||||||
@ -98,8 +104,6 @@ pub(crate) fn handle_start(
|
|||||||
} else {
|
} else {
|
||||||
TagKind::Figure.with_alt_text(alt)
|
TagKind::Figure.with_alt_text(alt)
|
||||||
}
|
}
|
||||||
} else if let Some(_) = elem.to_packed::<FigureCaption>() {
|
|
||||||
TagKind::Caption.into()
|
|
||||||
} else if let Some(table) = elem.to_packed::<TableElem>() {
|
} else if let Some(table) = elem.to_packed::<TableElem>() {
|
||||||
let table_id = gc.tags.next_table_id();
|
let table_id = gc.tags.next_table_id();
|
||||||
let summary = table.summary.get_as_ref().map(|s| s.to_string());
|
let summary = table.summary.get_as_ref().map(|s| s.to_string());
|
||||||
@ -391,18 +395,20 @@ impl Tags {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub(crate) struct TableId(u32);
|
pub(crate) struct TableId(u32);
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub(crate) struct LinkId(u32);
|
pub(crate) struct LinkId(u32);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct StackEntry {
|
pub(crate) struct StackEntry {
|
||||||
pub(crate) loc: Location,
|
pub(crate) loc: Location,
|
||||||
pub(crate) kind: StackEntryKind,
|
pub(crate) kind: StackEntryKind,
|
||||||
pub(crate) nodes: Vec<TagNode>,
|
pub(crate) nodes: Vec<TagNode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) enum StackEntryKind {
|
pub(crate) enum StackEntryKind {
|
||||||
Standard(Tag),
|
Standard(Tag),
|
||||||
Outline(OutlineCtx),
|
Outline(OutlineCtx),
|
||||||
|
@ -4,6 +4,7 @@ use typst_library::model::OutlineEntry;
|
|||||||
|
|
||||||
use crate::tags::TagNode;
|
use crate::tags::TagNode;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct OutlineCtx {
|
pub(crate) struct OutlineCtx {
|
||||||
stack: Vec<OutlineSection>,
|
stack: Vec<OutlineSection>,
|
||||||
}
|
}
|
||||||
@ -52,6 +53,7 @@ impl OutlineCtx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct OutlineSection {
|
pub(crate) struct OutlineSection {
|
||||||
entries: Vec<TagNode>,
|
entries: Vec<TagNode>,
|
||||||
}
|
}
|
||||||
|
@ -12,15 +12,17 @@ use typst_library::pdf::{TableCellKind, TableHeaderScope};
|
|||||||
|
|
||||||
use crate::tags::{TableId, TagNode};
|
use crate::tags::{TableId, TagNode};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct TableCtx {
|
pub(crate) struct TableCtx {
|
||||||
pub(crate) id: TableId,
|
pub(crate) id: TableId,
|
||||||
pub(crate) summary: Option<String>,
|
pub(crate) summary: Option<String>,
|
||||||
rows: Vec<Vec<GridCell>>,
|
rows: Vec<Vec<GridCell>>,
|
||||||
|
min_width: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableCtx {
|
impl TableCtx {
|
||||||
pub(crate) fn new(id: TableId, summary: Option<String>) -> Self {
|
pub(crate) fn new(id: TableId, summary: Option<String>) -> Self {
|
||||||
Self { id, summary, rows: Vec::new() }
|
Self { id, summary, rows: Vec::new(), min_width: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, x: usize, y: usize) -> Option<&TableCtxCell> {
|
fn get(&self, x: usize, y: usize) -> Option<&TableCtxCell> {
|
||||||
@ -64,14 +66,15 @@ impl TableCtx {
|
|||||||
|
|
||||||
// Extend the table grid to fit this cell.
|
// Extend the table grid to fit this cell.
|
||||||
let required_height = y + rowspan.get();
|
let required_height = y + rowspan.get();
|
||||||
let required_width = x + colspan.get();
|
self.min_width = self.min_width.max(x + colspan.get());
|
||||||
if self.rows.len() < required_height {
|
if self.rows.len() < required_height {
|
||||||
self.rows
|
self.rows
|
||||||
.resize(required_height, vec![GridCell::Missing; required_width]);
|
.resize(required_height, vec![GridCell::Missing; self.min_width]);
|
||||||
}
|
}
|
||||||
let row = &mut self.rows[y];
|
for row in self.rows.iter_mut() {
|
||||||
if row.len() < required_width {
|
if row.len() < self.min_width {
|
||||||
row.resize_with(required_width, || GridCell::Missing);
|
row.resize_with(self.min_width, || GridCell::Missing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store references to the cell for all spanned cells.
|
// Store references to the cell for all spanned cells.
|
||||||
@ -180,11 +183,7 @@ impl TableCtx {
|
|||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
};
|
};
|
||||||
|
Some(TagNode::Group(tag, cell.nodes))
|
||||||
// Wrap content in a paragraph.
|
|
||||||
// TODO: maybe avoid nested paragraphs?
|
|
||||||
let par = TagNode::Group(TagKind::P.into(), cell.nodes);
|
|
||||||
Some(TagNode::Group(tag, vec![par]))
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@ -254,7 +253,7 @@ impl TableCtx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
enum GridCell {
|
enum GridCell {
|
||||||
Cell(TableCtxCell),
|
Cell(TableCtxCell),
|
||||||
Spanned(usize, usize),
|
Spanned(usize, usize),
|
||||||
@ -288,7 +287,7 @@ impl GridCell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
struct TableCtxCell {
|
struct TableCtxCell {
|
||||||
x: u32,
|
x: u32,
|
||||||
y: u32,
|
y: u32,
|
||||||
@ -422,7 +421,7 @@ mod tests {
|
|||||||
TagNode::Group(
|
TagNode::Group(
|
||||||
TagKind::TH(TableHeaderCell::new(scope).with_headers(TagIdRefs { ids }))
|
TagKind::TH(TableHeaderCell::new(scope).with_headers(TagIdRefs { ids }))
|
||||||
.with_id(Some(id)),
|
.with_id(Some(id)),
|
||||||
vec![TagNode::Group(TagKind::P.into(), Vec::new())],
|
Vec::new(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,7 +432,7 @@ mod tests {
|
|||||||
.collect();
|
.collect();
|
||||||
TagNode::Group(
|
TagNode::Group(
|
||||||
TagKind::TD(TableDataCell::new().with_headers(TagIdRefs { ids })).into(),
|
TagKind::TD(TableDataCell::new().with_headers(TagIdRefs { ids })).into(),
|
||||||
vec![TagNode::Group(TagKind::P.into(), Vec::new())],
|
Vec::new(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user