Skip to main content

tex_engine/tex/nodes/
horizontal.rs

1/*! Nodes allowed in horizontal lists. */
2use crate::engine::filesystem::{File, SourceRef, SourceReference};
3use crate::engine::fontsystem::{Font, FontSystem};
4use crate::engine::EngineTypes;
5use crate::tex::characters::Character;
6use crate::tex::nodes::boxes::{HBoxInfo, TeXBox};
7use crate::tex::nodes::math::MathGroup;
8use crate::tex::nodes::vertical::VNode;
9use crate::tex::nodes::{display_do_indent, BoxTarget, Leaders, NodeTrait, NodeType, WhatsitNode};
10use crate::tex::numerics::Skip;
11use crate::tex::numerics::TeXDimen;
12use crate::tex::tokens::token_lists::TokenList;
13
14/// A horizontal list node.
15#[derive(Clone, Debug)]
16pub enum HNode<ET: EngineTypes> {
17    /// A penalty node, as produced by `\penalty`.
18    Penalty(i32),
19    /// A mark node, as produced by `\mark`.
20    Mark(usize, TokenList<ET::Token>),
21    /// A whatsit node, as produced by `\special`, `\write`, etc.
22    Whatsit(WhatsitNode<ET>),
23    /// A glue node, as produced by `\hskip`.
24    HSkip(Skip<ET::Dim>),
25    /// A glue node, as produced by `\hfil`.
26    HFil,
27    /// A glue node, as produced by `\hfill`.
28    HFill,
29    /// A glue node, as produced by `\hfilneg`.
30    HFilneg,
31    /// A glue node, as produced by `\hss`.
32    Hss,
33    /// A glue node, as produced by a space character.
34    Space,
35    /// A kern node, as produced by `\kern`.
36    HKern(ET::Dim),
37    /// Leaders, as produced by `\leaders` or `\cleaders` or `\xleaders`.
38    Leaders(Leaders<ET>),
39    /// A box node, as produced by `\hbox`, `\vbox`, `\vtop`, etc.
40    Box(TeXBox<ET>),
41    /// A rule node, as produced by `\vrule`.
42    VRule {
43        /// The *provided* width of the rule.
44        width: Option<ET::Dim>,
45        /// The *provided* height of the rule.
46        height: Option<ET::Dim>,
47        /// The *provided* depth of the rule.
48        depth: Option<ET::Dim>,
49        /// The source reference for the start of the rule.
50        start: SourceRef<ET>,
51        /// The source reference for the end of the rule.
52        end: SourceRef<ET>,
53    },
54    /// An insertion node, as produced by `\insert`.
55    Insert(usize, Box<[VNode<ET>]>),
56    /// A vadjust node, as produced by `\vadjust`; its contents will migrate to the surrounding vertical list eventually.
57    VAdjust(Box<[VNode<ET>]>),
58    /// A math list, as produced by `$...$` or `$$...$$`.
59    MathGroup(MathGroup<ET>),
60    /// A character node, as produced by a character.
61    Char {
62        /// The character.
63        char: ET::Char,
64        /// The current font
65        font: <ET::FontSystem as FontSystem>::Font,
66    },
67    /// An `\accent` node.
68    Accent {
69        /// The accent character.
70        accent: ET::Char,
71        /// The lower character.
72        char: ET::Char,
73        /// The current font
74        font: <ET::FontSystem as FontSystem>::Font,
75    },
76    /// A custom node.
77    Custom(ET::CustomNode),
78}
79
80impl<ET: EngineTypes> NodeTrait<ET> for HNode<ET> {
81    fn display_fmt(&self, indent: usize, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82        match self {
83            HNode::Penalty(p) => {
84                display_do_indent(indent, f)?;
85                write!(f, "<penalty:{}>", p)
86            }
87            HNode::Leaders(l) => l.display_fmt(indent, f),
88            HNode::Box(b) => b.display_fmt(indent, f),
89            HNode::Mark(i, _) => {
90                display_do_indent(indent, f)?;
91                write!(f, "<mark:{}>", i)
92            }
93            HNode::VRule {
94                width,
95                height,
96                depth,
97                ..
98            } => {
99                write!(f, "<vrule")?;
100                if let Some(w) = width {
101                    write!(f, " width={}", w)?;
102                }
103                if let Some(h) = height {
104                    write!(f, " height={}", h)?;
105                }
106                if let Some(d) = depth {
107                    write!(f, " depth={}", d)?;
108                }
109                write!(f, ">")
110            }
111            HNode::Insert(n, ch) => {
112                display_do_indent(indent, f)?;
113                write!(f, "<insert {}>", n)?;
114                for c in ch.iter() {
115                    c.display_fmt(indent + 2, f)?;
116                }
117                display_do_indent(indent, f)?;
118                write!(f, "</insert>")
119            }
120            HNode::VAdjust(ls) => {
121                display_do_indent(indent, f)?;
122                f.write_str("<vadjust>")?;
123                for c in ls.iter() {
124                    c.display_fmt(indent + 2, f)?;
125                }
126                display_do_indent(indent, f)?;
127                f.write_str("</vadjust>")
128            }
129            HNode::MathGroup(mg) => mg.display_fmt(indent, f),
130            HNode::Char { char, .. } => {
131                char.display_fmt(f);
132                Ok(())
133            }
134            HNode::Accent { accent, char, .. } => {
135                write!(
136                    f,
137                    "<accent accent=\"{}\" char=\"{}\" />",
138                    accent.display(),
139                    char.display()
140                )
141            }
142            HNode::Whatsit(w) => {
143                display_do_indent(indent, f)?;
144                write!(f, "{:?}", w)
145            }
146            HNode::HSkip(s) => write!(f, "<hskip:{}>", s),
147            HNode::HFil => write!(f, "<hfil>"),
148            HNode::HFill => write!(f, "<hfill>"),
149            HNode::HFilneg => write!(f, "<hfilneg>"),
150            HNode::Hss => write!(f, "<hss>"),
151            HNode::Space => write!(f, "<space>"),
152            HNode::HKern(d) => write!(f, "<hkern:{}>", d),
153            HNode::Custom(n) => n.display_fmt(indent, f),
154        }
155    }
156    fn height(&self) -> ET::Dim {
157        match self {
158            HNode::Box(b) => b.height(),
159            HNode::VRule { height, .. } => height.unwrap_or_default(),
160            HNode::Char { char, font } => font.get_ht(*char),
161            HNode::Leaders(l) => l.height(),
162            HNode::MathGroup(mg) => mg.height(),
163            HNode::Custom(n) => n.height(),
164            HNode::Accent { char, font, .. } => {
165                font.get_ht(*char) // TODO
166            }
167            _ => ET::Dim::default(),
168        }
169    }
170    fn width(&self) -> ET::Dim {
171        match self {
172            HNode::Box(b) => b.width(),
173            HNode::Char { char, font } => font.get_wd(*char),
174            HNode::VRule { width, .. } => width.unwrap_or(ET::Dim::from_sp(26214)),
175            HNode::Leaders(l) => l.width(),
176            HNode::MathGroup(mg) => mg.width(),
177            HNode::Custom(n) => n.width(),
178            HNode::HKern(d) => *d,
179            HNode::HSkip(s) => s.base,
180            HNode::Accent { char, font, .. } => font.get_wd(*char),
181            HNode::Space => ET::Dim::from_sp(65536 * 5), // TODO heuristic; use spacefactor instead
182            _ => ET::Dim::default(),
183        }
184    }
185    fn depth(&self) -> ET::Dim {
186        match self {
187            HNode::Box(b) => b.depth(),
188            HNode::Char { char, font } => font.get_dp(*char),
189            HNode::Accent { char, font, .. } => font.get_dp(*char),
190            HNode::VRule { depth, .. } => depth.unwrap_or_default(),
191            HNode::Leaders(l) => l.depth(),
192            HNode::MathGroup(mg) => mg.depth(),
193            HNode::Custom(n) => n.depth(),
194            _ => ET::Dim::default(),
195        }
196    }
197    fn nodetype(&self) -> NodeType {
198        match self {
199            HNode::Penalty(_) => NodeType::Penalty,
200            HNode::VRule { .. } => NodeType::Rule,
201            HNode::Box(b) => b.nodetype(),
202            HNode::Char { .. } => NodeType::Char,
203            HNode::HKern(_) => NodeType::Kern,
204            HNode::Insert(..) => NodeType::Insertion,
205            HNode::VAdjust(_) => NodeType::Adjust,
206            HNode::MathGroup { .. } => NodeType::Math,
207            HNode::Mark(_, _) => NodeType::Mark,
208            HNode::Whatsit(_) => NodeType::WhatsIt,
209            HNode::Accent { .. } => NodeType::Char,
210            HNode::Leaders(_) => NodeType::Glue,
211            HNode::HSkip(_)
212            | HNode::Space
213            | HNode::HFil
214            | HNode::HFill
215            | HNode::HFilneg
216            | HNode::Hss => NodeType::Glue,
217            HNode::Custom(n) => n.nodetype(),
218        }
219    }
220    fn opaque(&self) -> bool {
221        match self {
222            HNode::Mark(_, _) => true,
223            HNode::Custom(n) => n.opaque(),
224            _ => false,
225        }
226    }
227
228    fn sourceref(&self) -> Option<(&SourceRef<ET>, &SourceRef<ET>)> {
229        match self {
230            HNode::VRule { start, end, .. } => Some((start, end)),
231            HNode::Box(b) => b.sourceref(),
232            HNode::MathGroup(mg) => mg.sourceref(),
233            _ => None,
234        }
235    }
236}
237
238/// The kinds of horizontal lists that can occur.
239/// TODO: rethink this
240#[derive(Clone, Debug)]
241pub enum HorizontalNodeListType<ET: EngineTypes> {
242    /// A paragraph; will ultimately be broken into lines.
243    Paragraph(SourceReference<<ET::File as File>::SourceRefID>),
244    /// A horizontal box.
245    Box(HBoxInfo<ET>, SourceRef<ET>, BoxTarget<ET>),
246    /// A `\valign` list
247    VAlign,
248    /// A row in an `\halign`. The source ref indicates the start of the row.
249    HAlignRow(SourceRef<ET>),
250    /// A cell in an `\halign`. The source ref indicates the start of the cell.
251    /// The `u8` indicates the number of *additional* columns spanned by this cell
252    /// (so by default 0).
253    HAlignCell(SourceRef<ET>, u8),
254}