1use crate::Engine;
20use crate::nodes::{
21 DEFAULT_CODE, NodeData, NodeRef, accent_sub, fence_sub, id, noad_sub, radical_sub,
22};
23
24pub const STYLE_NAMES: [&str; 8] = [
26 "displaystyle",
27 "crampeddisplaystyle",
28 "textstyle",
29 "crampedtextstyle",
30 "scriptstyle",
31 "crampedscriptstyle",
32 "scriptscriptstyle",
33 "crampedscriptscriptstyle",
34];
35
36impl Engine {
37 pub fn print_style(&mut self, s: u32) {
39 match STYLE_NAMES.get(s as usize) {
40 Some(n) => self.print_esc_str(n),
41 None => self.printer.print_str("Unknown style!"),
42 }
43 }
44
45 pub fn print_fam_and_char(&mut self, p: NodeRef) {
48 let (fam, chr) = match self.nodes.data(p) {
49 NodeData::MathChar { fam, chr } => (*fam, *chr),
50 _ => (0, 0),
51 };
52 self.print_esc_str("fam");
53 self.printer.print_int(i64::from(fam));
54 self.printer.print_char(' ' as u32);
55 self.printer.print_char(chr);
56 }
57
58 pub fn print_delimiter(&mut self, p: NodeRef) {
60 let (sf, sc, lf, lc) = self.delim_fields(p);
61 let mut a = i64::from(sf) * 256 + i64::from(sc);
62 a = a * 0x1000 + i64::from(lf) * 256 + i64::from(lc);
63 if a < 0 {
64 self.printer.print_int(a);
65 } else {
66 self.printer.print_hex(a);
67 }
68 }
69
70 pub fn delim_fields(&self, p: NodeRef) -> (u32, u32, u32, u32) {
73 if p.is_null() {
74 return (0, 0, 0, 0);
75 }
76 match self.nodes.data(p) {
77 NodeData::Delim {
78 small_fam,
79 small_char,
80 large_fam,
81 large_char,
82 } => (*small_fam, *small_char, *large_fam, *large_char),
83 _ => (0, 0, 0, 0),
84 }
85 }
86
87 fn print_subsidiary_data(&mut self, p: NodeRef, c: u8) {
89 if self.ts.show_prefix.len() as i64 >= i64::from(self.depth_threshold) {
90 if !p.is_null() {
91 self.printer.print_str(" []");
92 }
93 return;
94 }
95 if p.is_null() {
96 return;
97 }
98 self.ts.show_prefix.push(c);
99 match self.nodes.data(p) {
100 NodeData::MathChar { .. } => {
101 self.printer.print_ln();
102 self.print_current_prefix();
103 self.print_fam_and_char(p);
104 }
105 NodeData::SubList { head } => {
106 let head = *head;
107 if self.nodes.id(p) == id::SUB_MLIST && head.is_null() {
108 self.printer.print_ln();
109 self.print_current_prefix();
110 self.printer.print_str("{}");
111 } else {
112 self.show_node_list(head);
113 }
114 }
115 _ => {}
116 }
117 self.ts.show_prefix.pop();
118 }
119
120 fn print_current_prefix(&mut self) {
121 let s = std::mem::take(&mut self.ts.show_prefix);
122 for &b in &s {
123 self.printer.print_char(u32::from(b));
124 }
125 self.ts.show_prefix = s;
126 }
127
128 fn show_list_with(&mut self, p: NodeRef, c: u8) {
129 self.ts.show_prefix.push(c);
130 self.show_node_list(p);
131 self.ts.show_prefix.pop();
132 }
133
134 pub fn display_math_node(&mut self, p: NodeRef) -> bool {
136 let nid = self.nodes.id(p);
137 let sub = self.nodes.subtype(p);
138 match self.nodes.data(p).clone() {
139 NodeData::Style { style } => self.print_style(u32::from(style)),
140 NodeData::Choice(c) => {
141 self.print_esc_str("mathchoice");
142 for (l, ch) in c.iter().zip([b'D', b'T', b'S', b's']) {
143 self.show_list_with(*l, ch);
144 }
145 }
146 NodeData::Noad(n) => {
147 match nid {
148 id::RADICAL => {
149 let name = match sub {
150 radical_sub::UROOT => "Uroot",
151 radical_sub::UUNDERDELIMITER => "Uunderdelimiter",
152 radical_sub::UOVERDELIMITER => "Uoverdelimiter",
153 radical_sub::UDELIMITERUNDER => "Udelimiterunder",
154 radical_sub::UDELIMITEROVER => "Udelimiterover",
155 radical_sub::UHEXTENSIBLE => "Uhextensible",
156 _ => "radical",
157 };
158 self.print_esc_str(name);
159 self.print_delimiter(n.left);
160 if n.width != 0 {
161 self.printer.print_str("width=");
162 self.printer.print_scaled(n.width);
163 self.printer.print_char(' ' as u32);
164 }
165 if !n.degree.is_null() {
166 self.print_subsidiary_data(n.degree, b'/');
167 }
168 }
169 id::ACCENT => {
170 self.print_esc_str("Umathaccent");
171 let (top, bot) = (!n.accent.is_null(), !n.bot_accent.is_null());
172 if top && bot {
173 self.printer.print_str(" both");
174 } else if bot {
175 self.printer.print_str(" bottom");
176 }
177 if n.options & crate::nodes::noad_opt::OVERLAY != 0 {
178 self.printer.print_str(" overlay");
179 }
180 if n.fraction != 0 {
181 self.printer.print_str(" fraction=");
182 self.printer.print_int(i64::from(n.fraction));
183 self.printer.print_char(' ' as u32);
184 }
185 if top {
186 if sub == accent_sub::FIXED_TOP || sub == accent_sub::FIXED_BOTH {
187 self.printer.print_str(" fixed ");
188 }
189 self.print_fam_and_char(n.accent);
190 }
191 if bot {
192 if sub == accent_sub::FIXED_BOTTOM || sub == accent_sub::FIXED_BOTH {
193 self.printer.print_str(" fixed ");
194 }
195 self.print_fam_and_char(n.bot_accent);
196 }
197 }
198 _ => {
199 let name = match sub {
200 noad_sub::ORD => "mathord",
201 noad_sub::OP_DISPLAY_LIMITS
202 | noad_sub::OP_LIMITS
203 | noad_sub::OP_NO_LIMITS => "mathop",
204 noad_sub::BIN => "mathbin",
205 noad_sub::REL => "mathrel",
206 noad_sub::OPEN => "mathopen",
207 noad_sub::CLOSE => "mathclose",
208 noad_sub::PUNCT => "mathpunct",
209 noad_sub::INNER => "mathinner",
210 noad_sub::UNDER => "underline",
211 noad_sub::OVER => "overline",
212 _ => "vcenter",
213 };
214 self.print_esc_str(name);
215 if sub == noad_sub::OP_LIMITS {
216 self.print_esc_str("limits");
217 } else if sub == noad_sub::OP_NO_LIMITS {
218 self.print_esc_str("nolimits");
219 }
220 }
221 }
222 self.print_subsidiary_data(n.nucleus, b'.');
223 self.print_subsidiary_data(n.sup, b'^');
224 self.print_subsidiary_data(n.sub, b'_');
225 }
226 NodeData::Fence(f) => {
227 self.print_esc_str(match sub {
228 fence_sub::LEFT => "left",
229 fence_sub::MIDDLE | fence_sub::NO => "middle",
230 _ => "right",
231 });
232 self.print_delimiter(f.delim);
233 }
234 NodeData::Fraction(f) => {
235 self.print_esc_str("fraction, thickness ");
236 if f.thickness == DEFAULT_CODE {
237 self.printer.print_str("= default");
238 } else {
239 self.printer.print_scaled(f.thickness);
240 }
241 if self.delim_fields(f.left) != (0, 0, 0, 0) {
242 self.printer.print_str(", left-delimiter ");
243 self.print_delimiter(f.left);
244 }
245 if self.delim_fields(f.right) != (0, 0, 0, 0) {
246 self.printer.print_str(", right-delimiter ");
247 self.print_delimiter(f.right);
248 }
249 self.print_subsidiary_data(f.num, b'\\');
250 self.print_subsidiary_data(f.denom, b'/');
251 }
252 _ => return false,
253 }
254 true
255 }
256}