Skip to main content

mathtex_engine/
host_box.rs

1use mathtex_ir::{FontKey, GlyphId, Length, Point};
2
3/// Answers `\hostbox{token}` with a box the host lays out, such as a nested editor field.
4pub trait HostBoxes {
5    /// The box for one placement of `request.token`, `None` renders nothing and emits a warning.
6    fn host_box(&self, request: &HostBoxRequest) -> Option<HostBox>;
7
8    /// A value that changes whenever the boxes for `token` change, `None` makes fragments using it uncachable.
9    fn revision(&self, _token: u32) -> Option<u64> {
10        None
11    }
12}
13
14impl<T> HostBoxes for &T
15where
16    T: HostBoxes + ?Sized,
17{
18    fn host_box(&self, request: &HostBoxRequest) -> Option<HostBox> {
19        (**self).host_box(request)
20    }
21
22    fn revision(&self, token: u32) -> Option<u64> {
23        (**self).revision(token)
24    }
25}
26
27/// Host boxes of a host that has none, every `\hostbox` renders nothing and emits a warning.
28#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
29pub struct NoHostBoxes;
30
31impl HostBoxes for NoHostBoxes {
32    fn host_box(&self, _request: &HostBoxRequest) -> Option<HostBox> {
33        None
34    }
35
36    fn revision(&self, _token: u32) -> Option<u64> {
37        Some(0)
38    }
39}
40
41/// Math style at a host box's placement, display style reports as text as TeX's size does.
42#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
43#[non_exhaustive]
44pub enum MathStyle {
45    /// Text or display style, the text size.
46    Text,
47    /// Script style.
48    Script,
49    /// Second level script style.
50    ScriptScript,
51}
52
53/// One placement of `\hostbox{token}`.
54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55#[non_exhaustive]
56pub struct HostBoxRequest {
57    /// The number the fragment wrote in `\hostbox{...}`.
58    pub token: u32,
59    /// Math style at the placement, text outside math.
60    pub style: MathStyle,
61    /// Size of the current font at the placement.
62    pub size: Length,
63}
64
65impl HostBoxRequest {
66    /// A request for `token` placed in `style` at font size `size`.
67    #[must_use]
68    pub fn new(token: u32, style: MathStyle, size: Length) -> Self {
69        Self { token, style, size }
70    }
71}
72
73/// A host laid out box, its runs and rules drawn relative to its baseline origin with y down.
74#[derive(Clone, Debug, PartialEq, Eq)]
75#[non_exhaustive]
76pub struct HostBox {
77    /// Width, which TeX spaces the box by.
78    pub width: Length,
79    /// Height above the baseline.
80    pub height: Length,
81    /// Depth below the baseline.
82    pub depth: Length,
83    /// Glyph runs drawn inside the box.
84    pub runs: Vec<HostBoxRun>,
85    /// Rules drawn inside the box.
86    pub rules: Vec<HostBoxRule>,
87}
88
89impl HostBox {
90    /// An empty box of the given size, a negative size is rejected with a warning when typeset.
91    #[must_use]
92    pub fn new(width: Length, height: Length, depth: Length) -> Self {
93        Self {
94            width,
95            height,
96            depth,
97            runs: Vec::new(),
98            rules: Vec::new(),
99        }
100    }
101
102    /// Adds a glyph run and returns the box.
103    #[must_use]
104    pub fn with_run(mut self, run: HostBoxRun) -> Self {
105        self.runs.push(run);
106        self
107    }
108
109    /// Adds a rule and returns the box.
110    #[must_use]
111    pub fn with_rule(mut self, rule: HostBoxRule) -> Self {
112        self.rules.push(rule);
113        self
114    }
115}
116
117/// Glyphs of one face inside a host box, the fragment carries the key so the host can draw them.
118#[derive(Clone, Debug, PartialEq, Eq)]
119#[non_exhaustive]
120pub struct HostBoxRun {
121    /// Key of the host's face.
122    pub font: FontKey,
123    /// Size the glyphs are drawn at.
124    pub size: Length,
125    /// Glyphs in drawing order.
126    pub glyphs: Vec<HostBoxGlyph>,
127}
128
129impl HostBoxRun {
130    /// A run of `glyphs` in face `font` at `size`.
131    #[must_use]
132    pub fn new(font: FontKey, size: Length, glyphs: Vec<HostBoxGlyph>) -> Self {
133        Self { font, size, glyphs }
134    }
135}
136
137/// A glyph at its baseline origin, relative to the box's baseline origin with y down.
138#[derive(Clone, Copy, Debug, PartialEq, Eq)]
139#[non_exhaustive]
140pub struct HostBoxGlyph {
141    /// Glyph index in the run's face.
142    pub glyph: GlyphId,
143    /// Baseline origin of the glyph.
144    pub origin: Point,
145}
146
147impl HostBoxGlyph {
148    /// Glyph `glyph` with its baseline origin at `origin`.
149    #[must_use]
150    pub fn new(glyph: GlyphId, origin: Point) -> Self {
151        Self { glyph, origin }
152    }
153}
154
155/// A filled rectangle whose bottom left corner is `origin`, relative to the box's baseline origin with y down.
156#[derive(Clone, Copy, Debug, PartialEq, Eq)]
157#[non_exhaustive]
158pub struct HostBoxRule {
159    /// Bottom left corner.
160    pub origin: Point,
161    /// Width to the right of the corner.
162    pub width: Length,
163    /// Height above the corner.
164    pub height: Length,
165}
166
167impl HostBoxRule {
168    /// A rule `width` wide and `height` tall above `origin`.
169    #[must_use]
170    pub fn new(origin: Point, width: Length, height: Length) -> Self {
171        Self {
172            origin,
173            width,
174            height,
175        }
176    }
177}