mod common;
use common::{SceneCommand, compile_page, default_provider, parse};
fn glyph_run_count(result: &common::CompileResult) -> usize {
result
.scene
.commands
.iter()
.filter(|c| matches!(c, SceneCommand::DrawGlyphRun { .. }))
.count()
}
fn flow_src() -> &'static str {
r##"zenith version=1 {
project id="proj.fl" name="FL"
tokens format="zenith-token-v1" {
token id="color.ink" type="color" value="#000000"
}
styles {}
document id="doc.fl" title="FL" {
page id="page.fl1" w=(px)400 h=(px)400 {
table id="src" flows="t" x=(px)20 y=(px)20 w=(px)360 h=(px)120 header-rows=1 cell-padding=(px)0 gap=(px)0 {
column
row { cell { text id="h" x=(px)0 y=(px)0 fill=(token)"color.ink" { span "HEAD" } } }
row { cell { text id="b1" x=(px)0 y=(px)0 fill=(token)"color.ink" { span "row-1" } } }
row { cell { text id="b2" x=(px)0 y=(px)0 fill=(token)"color.ink" { span "row-2" } } }
row { cell { text id="b3" x=(px)0 y=(px)0 fill=(token)"color.ink" { span "row-3" } } }
row { cell { text id="b4" x=(px)0 y=(px)0 fill=(token)"color.ink" { span "row-4" } } }
row { cell { text id="b5" x=(px)0 y=(px)0 fill=(token)"color.ink" { span "row-5" } } }
row { cell { text id="b6" x=(px)0 y=(px)0 fill=(token)"color.ink" { span "row-6" } } }
}
}
page id="page.fl2" w=(px)400 h=(px)400 {
table id="cont" flows="t" x=(px)20 y=(px)20 w=(px)360 h=(px)400 header-rows=1 cell-padding=(px)0 gap=(px)0 {
column
}
}
}
}
"##
}
#[test]
fn flow_splits_body_and_repeats_header_across_pages() {
let doc = parse(flow_src());
let fonts = default_provider();
let p1 = compile_page(&doc, &fonts, 0, None);
let p2 = compile_page(&doc, &fonts, 1, None);
let c1 = glyph_run_count(&p1);
let c2 = glyph_run_count(&p2);
assert!(
c1 >= 1,
"page 1 must render header + a body slice; got {c1}"
);
assert!(
c2 >= 1,
"page 2 must render header + remaining body; got {c2}"
);
assert_eq!(
c1 + c2,
8,
"total runs = 6 body + 2 header copies; page1={c1} page2={c2}"
);
assert!(
c1 < 7,
"page 1 must not fit the whole source table; got {c1} runs"
);
assert!(c2 >= 2, "page 2 must carry overflow body rows; got {c2}");
}
fn flow_rowspan_src() -> &'static str {
r##"zenith version=1 {
project id="proj.fr" name="FR"
tokens format="zenith-token-v1" {
token id="color.ink" type="color" value="#000000"
}
styles {}
document id="doc.fr" title="FR" {
page id="page.fr1" w=(px)400 h=(px)400 {
table id="rsrc" flows="t" x=(px)20 y=(px)20 w=(px)360 h=(px)55 header-rows=1 cell-padding=(px)0 gap=(px)0 {
column
column
row { cell { text id="rh1" x=(px)0 y=(px)0 fill=(token)"color.ink" { span "H1" } }; cell { text id="rh2" x=(px)0 y=(px)0 fill=(token)"color.ink" { span "H2" } } }
row { cell { text id="ra1" x=(px)0 y=(px)0 fill=(token)"color.ink" { span "A1" } }; cell { text id="ra2" x=(px)0 y=(px)0 fill=(token)"color.ink" { span "A2" } } }
row { cell rowspan=2 { text id="span" x=(px)0 y=(px)0 fill=(token)"color.ink" { span "SPAN" } }; cell { text id="rb2" x=(px)0 y=(px)0 fill=(token)"color.ink" { span "B2" } } }
row { cell { text id="rc2" x=(px)0 y=(px)0 fill=(token)"color.ink" { span "C2" } } }
}
}
page id="page.fr2" w=(px)400 h=(px)400 {
table id="rcont" flows="t" x=(px)20 y=(px)20 w=(px)360 h=(px)400 header-rows=1 cell-padding=(px)0 gap=(px)0 {
column
column
}
}
}
}
"##
}
#[test]
fn flow_rowspan_group_not_split_across_pages() {
let doc = parse(flow_rowspan_src());
let fonts = default_provider();
let p1 = compile_page(&doc, &fonts, 0, None);
let p2 = compile_page(&doc, &fonts, 1, None);
let c1 = glyph_run_count(&p1);
let c2 = glyph_run_count(&p2);
assert!(
(2..=4).contains(&c1),
"page 1 = header + first body row, no rowspan group; got {c1}"
);
assert!(
c2 >= 4,
"page 2 must carry the repeated header + whole rowspan group; got {c2}"
);
}