1use super::fmt::{parse_brc80, parse_brc97, parse_shd80, parse_shd_operand, Border, Shading};
7use super::sprm::{self, Sprm};
8
9#[derive(Debug, Default, Clone)]
10pub struct TableCell {
11 pub boundary_left: i32,
13 pub boundary_right: i32,
14 pub f_first_merged: bool,
15 pub f_merged: bool,
16 pub f_vert_merge: bool,
17 pub f_vert_restart: bool,
18 pub f_vertical: bool,
19 pub f_backward: bool,
20 pub vert_align: u8,
21 pub brc_top: Option<Border>,
22 pub brc_left: Option<Border>,
23 pub brc_bottom: Option<Border>,
24 pub brc_right: Option<Border>,
25 pub shd: Option<Shading>,
26}
27
28#[derive(Debug, Default, Clone)]
29pub struct Tap {
30 pub jc: u8,
31 pub dxa_gap_half: i16,
32 pub dya_row_height: i16,
33 pub f_cant_split: bool,
34 pub f_table_header: bool,
35 pub cells: Vec<TableCell>,
36 pub table_borders: [Option<Border>; 6], cell_padding_default: [Option<u16>; 4],
38 cell_padding: Vec<[Option<u16>; 4]>,
39}
40
41impl Tap {
42 pub fn from_grpprl(grpprl: &[u8]) -> Tap {
43 let mut tap = Tap::default();
44 let mut shd_queue: Vec<Shading> = Vec::new();
45 let mut shd_assigned = 0usize;
46 for sprm in sprm::iterate(grpprl) {
47 tap.apply_sprm(&sprm, &mut shd_queue, &mut shd_assigned);
48 }
49 for (index, shading) in shd_queue.into_iter().enumerate() {
51 if let Some(cell) = tap.cells.get_mut(index) {
52 if cell.shd.is_none() && shading.is_visible() {
53 cell.shd = Some(shading);
54 }
55 }
56 }
57 tap
58 }
59
60 fn apply_sprm(
61 &mut self,
62 sprm: &Sprm<'_>,
63 shd_queue: &mut Vec<Shading>,
64 shd_assigned: &mut usize,
65 ) {
66 match sprm.opcode {
67 0x5400 | 0x548A => self.jc = sprm.byte(),
68 0x9602 => self.dxa_gap_half = sprm.i16_operand(),
69 0x9407 => self.dya_row_height = sprm.i16_operand(),
70 0x3403 => self.f_cant_split = sprm.byte() == 1,
71 0x3404 => self.f_table_header = sprm.byte() == 1,
72 0xD608 => self.apply_tdef_table(sprm.operand),
73 0xD605 => {
74 for (index, chunk) in sprm.operand.chunks_exact(4).take(6).enumerate() {
75 self.table_borders[index] = parse_brc80(chunk);
76 }
77 }
78 0xD613 => {
79 for (index, chunk) in sprm.operand.chunks_exact(8).take(6).enumerate() {
80 let border = parse_brc97(chunk);
81 if border.is_some() {
82 self.table_borders[index] = border;
83 }
84 }
85 }
86 0xD609 => {
87 for chunk in sprm.operand.chunks_exact(2) {
89 if let Some(shading) = parse_shd80(u16::from_le_bytes([chunk[0], chunk[1]])) {
90 shd_queue.push(shading);
91 }
92 }
93 let _ = shd_assigned;
94 }
95 0xD612 => {
96 for chunk in sprm.operand.chunks_exact(10) {
98 if let Some(shading) = parse_shd_operand(chunk) {
99 shd_queue.push(shading);
100 }
101 }
102 }
103 0xD620 => self.apply_set_brc80(sprm.operand),
104 0xD632 => self.apply_cell_padding(sprm.operand, false),
105 0xD634 => self.apply_cell_padding(sprm.operand, true),
106 0xD62B => {
107 if sprm.operand.len() >= 2 {
109 let itc = sprm.operand[0] as usize;
110 let code = sprm.operand[1];
111 if let Some(cell) = self.cells.get_mut(itc) {
112 cell.f_vert_merge = code & 0x01 != 0;
113 cell.f_vert_restart = code & 0x02 != 0;
114 }
115 }
116 }
117 0xD62C => {
118 if sprm.operand.len() >= 3 {
120 let first = sprm.operand[0] as usize;
121 let lim = sprm.operand[1] as usize;
122 for itc in first..lim.min(self.cells.len()) {
123 self.cells[itc].vert_align = sprm.operand[2];
124 }
125 }
126 }
127 0x7627 | 0x7628 => {
128 if sprm.operand.len() >= 4 {
131 let first = sprm.operand[0] as usize;
132 let lim = sprm.operand[1] as usize;
133 let shading = parse_shd80(u16::from_le_bytes([sprm.operand[2], sprm.operand[3]]));
134 if let Some(shading) = shading {
135 for itc in first..lim.min(self.cells.len()) {
136 self.cells[itc].shd = Some(shading.clone());
137 }
138 }
139 }
140 }
141 _ => {}
142 }
143 }
144
145 fn apply_tdef_table(&mut self, operand: &[u8]) {
147 let Some(&itc_mac) = operand.first() else {
148 return;
149 };
150 let count = itc_mac as usize;
151 let centers_end = 1 + (count + 1) * 2;
152 if operand.len() < centers_end || count == 0 {
153 return;
154 }
155 let mut centers = Vec::with_capacity(count + 1);
156 for index in 0..=count {
157 let offset = 1 + index * 2;
158 centers.push(i16::from_le_bytes([operand[offset], operand[offset + 1]]) as i32);
159 }
160
161 self.cells = (0..count)
162 .map(|index| {
163 let mut cell = TableCell {
164 boundary_left: centers[index],
165 boundary_right: centers[index + 1],
166 ..TableCell::default()
167 };
168 let tc_offset = centers_end + index * 20;
169 if let Some(tc) = operand.get(tc_offset..tc_offset + 20) {
170 let rgf = u16::from_le_bytes([tc[0], tc[1]]);
171 cell.f_first_merged = rgf & 0x0001 != 0;
172 cell.f_merged = rgf & 0x0002 != 0;
173 cell.f_vertical = rgf & 0x0004 != 0;
174 cell.f_backward = rgf & 0x0008 != 0;
175 cell.f_vert_merge = rgf & 0x0020 != 0;
176 cell.f_vert_restart = rgf & 0x0040 != 0;
177 cell.vert_align = ((rgf >> 7) & 0x3) as u8;
178 cell.brc_top = parse_brc80(&tc[4..8]);
179 cell.brc_left = parse_brc80(&tc[8..12]);
180 cell.brc_bottom = parse_brc80(&tc[12..16]);
181 cell.brc_right = parse_brc80(&tc[16..20]);
182 }
183 cell
184 })
185 .collect();
186 }
187
188 fn apply_set_brc80(&mut self, operand: &[u8]) {
191 if operand.len() < 7 {
192 return;
193 }
194 let first = operand[0] as usize;
195 let lim = operand[1] as usize;
196 let grfbrc = operand[2];
197 let border = parse_brc80(&operand[3..7]);
198 for itc in first..lim.min(self.cells.len()) {
199 let cell = &mut self.cells[itc];
200 if grfbrc & 0x01 != 0 {
201 cell.brc_top = border.clone();
202 }
203 if grfbrc & 0x02 != 0 {
204 cell.brc_left = border.clone();
205 }
206 if grfbrc & 0x04 != 0 {
207 cell.brc_bottom = border.clone();
208 }
209 if grfbrc & 0x08 != 0 {
210 cell.brc_right = border.clone();
211 }
212 }
213 }
214
215 pub fn row_left_edge(&self) -> i32 {
216 self.cells.first().map(|cell| cell.boundary_left).unwrap_or(0)
217 }
218
219 fn apply_cell_padding(&mut self, operand: &[u8], row_default: bool) {
220 if operand.len() != 6 || operand[2] & !0x0F != 0 {
221 return;
222 }
223 let first = operand[0] as usize;
224 let limit = operand[1] as usize;
225 if first >= limit || limit > 64 || (row_default && (first != 0 || limit != 1)) {
226 return;
227 }
228 let width = u16::from_le_bytes([operand[4], operand[5]]);
229 let width = match operand[3] {
230 0 if width == 0 => None,
231 3 if width <= 31680 => Some(width),
232 _ => return,
233 };
234 let apply = |padding: &mut [Option<u16>; 4]| {
235 for (side, value) in padding.iter_mut().enumerate() {
236 if operand[2] & (1 << side) != 0 {
237 *value = width;
238 }
239 }
240 };
241 if row_default {
242 apply(&mut self.cell_padding_default);
243 } else {
244 self.cell_padding
245 .resize(self.cell_padding.len().max(limit), [None; 4]);
246 for padding in &mut self.cell_padding[first..limit] {
247 apply(padding);
248 }
249 }
250 }
251
252 pub fn default_cell_padding_twips(&self) -> [u16; 4] {
253 let gap = self.dxa_gap_half.max(0) as u16;
254 let fallback = [0, gap, 0, gap];
255 std::array::from_fn(|side| self.cell_padding_default[side].unwrap_or(fallback[side]))
256 }
257
258 pub fn cell_padding_twips(&self, cell_index: usize) -> [u16; 4] {
259 let defaults = self.default_cell_padding_twips();
260 std::array::from_fn(|side| {
261 self.cell_padding
262 .get(cell_index)
263 .and_then(|padding| padding[side])
264 .unwrap_or(defaults[side])
265 })
266 }
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272
273 fn tdef_operand(centers: &[i16], tc_flags: &[u16]) -> Vec<u8> {
274 let count = centers.len() - 1;
275 let mut operand = vec![count as u8];
276 for center in centers {
277 operand.extend_from_slice(¢er.to_le_bytes());
278 }
279 for index in 0..count {
280 let mut tc = [0u8; 20];
281 tc[..2].copy_from_slice(&tc_flags.get(index).copied().unwrap_or(0).to_le_bytes());
282 operand.extend_from_slice(&tc);
283 }
284 operand
285 }
286
287 #[test]
288 fn parses_tdef_table_boundaries() {
289 let operand = tdef_operand(&[0, 2400, 4800, 9360], &[0, 0, 0]);
290 let mut grpprl: Vec<u8> = vec![0x08, 0xD6];
291 grpprl.extend_from_slice(&((operand.len() + 1) as u16).to_le_bytes());
292 grpprl.extend_from_slice(&operand);
293
294 let tap = Tap::from_grpprl(&grpprl);
295 assert_eq!(tap.cells.len(), 3);
296 assert_eq!(tap.cells[0].boundary_left, 0);
297 assert_eq!(tap.cells[0].boundary_right, 2400);
298 assert_eq!(tap.cells[2].boundary_right, 9360);
299 }
300
301 #[test]
302 fn parses_vert_merge_flags() {
303 let operand = tdef_operand(&[0, 1000, 2000], &[0x0040, 0x0020]);
304 let mut grpprl: Vec<u8> = vec![0x08, 0xD6];
305 grpprl.extend_from_slice(&((operand.len() + 1) as u16).to_le_bytes());
306 grpprl.extend_from_slice(&operand);
307
308 let tap = Tap::from_grpprl(&grpprl);
309 assert!(tap.cells[0].f_vert_restart);
310 assert!(tap.cells[1].f_vert_merge);
311 assert!(!tap.cells[1].f_vert_restart);
312 }
313}