Skip to main content

latexml_core/alignment/
cell.rs

1use libxml::tree::Node;
2
3use super::template::{Align, BorderSpec, ColumnSpec};
4use crate::{
5  common::{dimension::Dimension, glue::Glue},
6  digested::Digested,
7  tokens::Tokens,
8};
9
10#[derive(Debug, Clone, Default, PartialEq)]
11pub struct Cell {
12  pub empty:               bool,
13  pub skippable:           bool,
14  pub omitted:             bool,
15  pub skipped:             bool,
16  pub thead_in_row:        bool,
17  pub thead_in_column:     bool,
18  pub before:              Option<Tokens>,
19  pub after:               Option<Tokens>,
20  pub align:               Option<Align>,
21  pub width:               Option<Dimension>,
22  pub height:              Option<Dimension>,
23  pub depth:               Option<Dimension>,
24  pub cached_width:        Option<Dimension>,
25  pub cached_height:       Option<Dimension>,
26  pub cached_depth:        Option<Dimension>,
27  pub colspan:             Option<usize>,
28  pub colspanned:          Option<usize>,
29  pub rowspan:             Option<usize>,
30  pub rowspanned:          Option<usize>,
31  pub boxes:               Option<Digested>,
32  pub cell_type:           Option<char>,
33  pub content_class:       Option<ColumnSpec>,
34  pub content_length:      Option<usize>,
35  pub border_left:         Option<usize>,
36  pub border_right:        Option<usize>,
37  pub border_top:          Option<usize>,
38  pub border_bottom:       Option<usize>,
39  pub top_padding:         Option<usize>,
40  pub bottom_padding:      Option<usize>,
41  pub right_padding:       Option<usize>,
42  pub left_padding:        Option<usize>,
43  pub vattach:             Option<String>,
44  pub cell:                Option<Node>,
45  pub x:                   Option<Dimension>,
46  pub y:                   Option<Dimension>,
47  pub border:              String,
48  /// Perl: $$colspec{tabskip} — intercolumn glue from \halign template
49  pub tabskip:             Option<Glue>,
50  /// Perl: $$colspec{lspaces} — left-side spacing (incl. tabskip)
51  pub lspaces:             Option<Digested>,
52  /// Perl: $$colspec{rspaces} — right-side spacing
53  pub rspaces:             Option<Digested>,
54  /// Perl: $$cell{class} — CSS class for the cell
55  pub class:               Option<String>,
56  /// Whether this column has \lx@intercol in its before tokens (from template).
57  /// Set during template building, used by nopad heuristic to distinguish
58  /// regular columns (has intercolumn padding) from @{}-disabled columns.
59  pub has_intercol_before: bool,
60  /// Whether this column has \lx@intercol in its after tokens (from template).
61  /// Set during template building, used by nopad heuristic to distinguish
62  /// regular columns (has intercolumn padding) from @{}-disabled columns.
63  pub has_intercol_after:  bool,
64  /// Background color from \columncolor/\cellcolor (set during digestion by \@setcellcolor)
65  pub backgroundcolor:     Option<String>,
66}
67impl Cell {
68  pub fn border_at(&self, side: BorderSpec) -> Option<usize> {
69    match side {
70      BorderSpec::Left => self.border_left,
71      BorderSpec::Right => self.border_right,
72      BorderSpec::Top => self.border_top,
73      BorderSpec::Bottom => self.border_bottom,
74    }
75  }
76}
77
78#[cfg(test)]
79mod tests {
80  use super::*;
81
82  #[test]
83  fn cell_default_flags_all_false() {
84    let c = Cell::default();
85    assert!(!c.empty);
86    assert!(!c.skippable);
87    assert!(!c.omitted);
88    assert!(!c.skipped);
89    assert!(!c.thead_in_row);
90    assert!(!c.thead_in_column);
91    assert!(!c.has_intercol_before);
92    assert!(!c.has_intercol_after);
93  }
94
95  #[test]
96  fn cell_default_options_all_none() {
97    let c = Cell::default();
98    assert!(c.before.is_none());
99    assert!(c.after.is_none());
100    assert!(c.align.is_none());
101    assert!(c.width.is_none());
102    assert!(c.height.is_none());
103    assert!(c.depth.is_none());
104    assert!(c.cached_width.is_none());
105    assert!(c.cached_height.is_none());
106    assert!(c.cached_depth.is_none());
107    assert!(c.colspan.is_none());
108    assert!(c.colspanned.is_none());
109    assert!(c.rowspan.is_none());
110    assert!(c.rowspanned.is_none());
111    assert!(c.boxes.is_none());
112    assert!(c.cell_type.is_none());
113    assert!(c.border_left.is_none());
114    assert!(c.border_right.is_none());
115    assert!(c.border_top.is_none());
116    assert!(c.border_bottom.is_none());
117    assert!(c.backgroundcolor.is_none());
118  }
119
120  #[test]
121  fn cell_default_border_is_empty_string() {
122    let c = Cell::default();
123    assert_eq!(c.border, "");
124  }
125
126  #[test]
127  fn cell_border_at_reads_correct_side() {
128    let c = Cell {
129      border_left: Some(1),
130      border_right: Some(2),
131      border_top: Some(3),
132      border_bottom: Some(4),
133      ..Default::default()
134    };
135    assert_eq!(c.border_at(BorderSpec::Left), Some(1));
136    assert_eq!(c.border_at(BorderSpec::Right), Some(2));
137    assert_eq!(c.border_at(BorderSpec::Top), Some(3));
138    assert_eq!(c.border_at(BorderSpec::Bottom), Some(4));
139  }
140
141  #[test]
142  fn cell_border_at_none_by_default() {
143    let c = Cell::default();
144    assert_eq!(c.border_at(BorderSpec::Left), None);
145    assert_eq!(c.border_at(BorderSpec::Right), None);
146    assert_eq!(c.border_at(BorderSpec::Top), None);
147    assert_eq!(c.border_at(BorderSpec::Bottom), None);
148  }
149
150  #[test]
151  fn cell_partial_eq_defaults() {
152    // Default cells are equal.
153    let a = Cell::default();
154    let b = Cell::default();
155    assert_eq!(a, b);
156  }
157
158  #[test]
159  fn cell_partial_eq_distinguishes_flags() {
160    let mut a = Cell::default();
161    let b = Cell::default();
162    a.empty = true;
163    assert_ne!(a, b);
164  }
165}