Skip to main content

mathtex_engine/
emit.rs

1use alloc::vec::Vec;
2
3use mathtex_ir::{
4    Fragment, FragmentMetadata, Glue, GlyphRun, Kern, LayoutBox, LayoutList, LayoutNode,
5    LayoutNodeKind, ListKind, NodeId, Point, Rect, Rule, Style, Surface,
6};
7
8/// IR emitter for layout code, replacing TeX shipout.
9#[derive(Clone, Debug)]
10pub struct IrEmitter {
11    fragment: Fragment,
12    next_node: u32,
13}
14
15impl IrEmitter {
16    /// Creates a new emitter for a fragment with the given metadata.
17    #[must_use]
18    pub fn new(metadata: FragmentMetadata) -> Self {
19        Self {
20            fragment: Fragment {
21                metadata,
22                ..Fragment::default()
23            },
24            next_node: 0,
25        }
26    }
27
28    /// Sets the drawing surface dimensions for the current fragment.
29    pub fn set_surface(&mut self, surface: Surface) {
30        self.fragment.surface = surface;
31    }
32
33    /// Emits a box node and returns its identifier.
34    pub fn emit_box(&mut self, node: EmitNode, layout_box: LayoutBox) -> NodeId {
35        self.emit(node, LayoutNodeKind::Box(layout_box))
36    }
37
38    /// Emits a list node wrapping the given children and returns its identifier.
39    pub fn emit_list(&mut self, node: EmitNode, kind: ListKind, children: Vec<NodeId>) -> NodeId {
40        self.emit(node, LayoutNodeKind::List(LayoutList { kind, children }))
41    }
42
43    /// Emits a glyph run node and returns its identifier.
44    pub fn emit_glyph_run(&mut self, node: EmitNode, glyph_run: GlyphRun) -> NodeId {
45        self.emit(node, LayoutNodeKind::GlyphRun(glyph_run))
46    }
47
48    /// Emits a rule node and returns its identifier.
49    pub fn emit_rule(&mut self, node: EmitNode, rule: Rule) -> NodeId {
50        self.emit(node, LayoutNodeKind::Rule(rule))
51    }
52
53    /// Emits a glue node and returns its identifier.
54    pub fn emit_glue(&mut self, node: EmitNode, glue: Glue) -> NodeId {
55        self.emit(node, LayoutNodeKind::Glue(glue))
56    }
57
58    /// Emits a kern node and returns its identifier.
59    pub fn emit_kern(&mut self, node: EmitNode, kern: Kern) -> NodeId {
60        self.emit(node, LayoutNodeKind::Kern(kern))
61    }
62
63    /// Consumes the emitter and returns the completed fragment.
64    #[must_use]
65    pub fn finish(self) -> Fragment {
66        self.fragment
67    }
68
69    fn emit(&mut self, node: EmitNode, kind: LayoutNodeKind) -> NodeId {
70        let id = NodeId(self.next_node);
71        self.next_node += 1;
72
73        self.fragment.nodes.push(LayoutNode {
74            id,
75            origin: node.origin,
76            bounds: node.bounds,
77            primary_source: None,
78            style: node.style,
79            kind,
80        });
81
82        id
83    }
84}
85
86/// Geometry and style carried by a single layout node during emission.
87#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
88pub struct EmitNode {
89    /// Position of the node origin in fragment coordinates.
90    pub origin: Point,
91    /// Bounding box of the node in fragment coordinates.
92    pub bounds: Rect,
93    /// TeX style level applied to nodes within this region.
94    pub style: Style,
95}
96
97impl EmitNode {
98    /// Returns a copy of this node with the style set to `style`.
99    #[must_use]
100    pub fn with_style(mut self, style: Style) -> Self {
101        self.style = style;
102        self
103    }
104}
105