1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//! Break tokens: where layout continues, and the state carried across the break. Tokens are compared only
//! for equality.
use std::rc::Rc;
use crate::docx::{NoteKind, ParaStyle};
use super::story::StoryUnit;
/// Where the flow is in a block.
#[derive(Clone, Debug, Default)]
pub enum At {
/// The block's start.
#[default]
Start,
/// A paragraph continued from an earlier column: the piece its next line starts at.
Piece(usize),
/// A table: the next row.
Row(usize),
/// A table row split across columns (TABLE-41): the row and each cell's remaining units, rebased to 0. Shared by
/// identity: two tokens are equal only if they continue the same split.
RowPart { row: usize, rest: Rc<Vec<Vec<StoryUnit>>> },
}
impl PartialEq for At {
fn eq(&self, o: &Self) -> bool {
match (self, o) {
(At::Start, At::Start) => true,
(At::Piece(a), At::Piece(b)) | (At::Row(a), At::Row(b)) => a == b,
(At::RowPart { row: a, rest: x }, At::RowPart { row: b, rest: y }) => a == b && Rc::ptr_eq(x, y),
_ => false,
}
}
}
impl At {
/// The piece a paragraph's next line starts at, or a table's next row (0 at the start).
pub fn index(&self) -> usize {
match self {
At::Start => 0,
At::Piece(i) | At::Row(i) => *i,
At::RowPart { row, .. } => *row,
}
}
/// Whether the flow is at the block's start (no part of it placed yet).
pub fn at_start(&self) -> bool {
self.index() == 0 && !matches!(self, At::RowPart { .. })
}
/// A split row's remaining units.
pub fn rest(&self) -> Option<&Rc<Vec<Vec<StoryUnit>>>> {
match self {
At::RowPart { rest, .. } => Some(rest),
_ => None,
}
}
}
/// Where the flow is in a section's blocks.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct FlowToken {
pub block: usize,
pub at: At,
}
impl FlowToken {
/// The next block's start.
pub fn next_block(&mut self) {
self.block += 1;
self.at = At::Start;
}
}
/// State carried from one column into the next.
#[derive(Clone, Debug)]
pub struct FlowState {
pub prev: Option<Rc<ParaStyle>>,
pub prev_after: f64,
/// How the next column top was reached: true = the next paragraph keeps its space-before (PARA-2, COL-2).
pub keep_top: bool,
pub first_para: bool,
/// Footnote parts that continue on the next page (NOTE-6).
pub note_rest: Vec<NotePart>,
/// Body lines counted for line numbering in the current restart scope (LNUM-2).
pub line_no: i64,
/// COL-2: the space-before of a paragraph whose first line ended in a column break, kept by its continuation.
pub break_before: f64,
}
impl Default for FlowState {
fn default() -> Self {
FlowState { prev: None, prev_after: 0.0, keep_top: true, first_para: true, note_rest: Vec::new(), line_no: 0, break_before: 0.0 }
}
}
impl PartialEq for FlowState {
/// Equal when the next column would start the same way. States carrying note parts never compare equal (they
/// continue specific notes).
fn eq(&self, o: &Self) -> bool {
let style = match (&self.prev, &o.prev) {
(None, None) => true,
(Some(x), Some(y)) => Rc::ptr_eq(x, y) || **x == **y,
_ => false,
};
style
&& self.prev_after == o.prev_after
&& self.keep_top == o.keep_top
&& self.first_para == o.first_para
&& self.note_rest.is_empty()
&& o.note_rest.is_empty()
&& self.line_no == o.line_no
&& self.break_before == o.break_before
}
}
/// A note, or the part of one, in a note area: which note it is and its units (a continuation's rebased to 0).
#[derive(Clone, Debug)]
pub struct NotePart {
pub kind: NoteKind,
pub id: i64,
pub units: Vec<StoryUnit>,
}
impl NotePart {
/// The part's height: its last unit's bottom.
pub fn height(&self) -> f64 {
self.units.last().map_or(0.0, |u| u.top + u.height)
}
}
/// Where a page's body starts: the section, the flow position and the carried state. No page number: parity and
/// number enter only through the values they produce.
#[derive(Clone, Debug, PartialEq)]
pub struct PageToken {
pub section: usize,
pub flow: FlowToken,
pub state: FlowState,
}