1use crate::engine::filesystem::SourceRef;
4use crate::engine::stomach::methods::ParLineSpec;
5use crate::engine::EngineTypes;
6use crate::tex::nodes::horizontal::{HNode, HorizontalNodeListType};
7use crate::tex::nodes::math::{
8 MathAtom, MathClass, MathKernel, MathNode, MathNucleus, UnresolvedMathFontStyle,
9};
10use crate::tex::nodes::vertical::{VNode, VerticalNodeListType};
11use crate::tex::nodes::{display_do_indent, BoxTarget, NodeList, NodeTrait, NodeType};
12use crate::tex::numerics::Skip;
13use crate::tex::numerics::TeXDimen;
14use std::fmt::{Display, Formatter};
15
16#[cfg(feature = "multithreaded")]
17type Once<A> = std::sync::OnceLock<A>;
18#[cfg(not(feature = "multithreaded"))]
19type Once<A> = std::cell::OnceCell<A>;
20
21#[derive(Clone, Copy, Eq, PartialEq, Debug)]
23pub enum BoxType {
24 Horizontal,
26 Vertical,
28}
29impl BoxType {
30 pub fn other(&self) -> Self {
32 match self {
33 BoxType::Horizontal => BoxType::Vertical,
34 BoxType::Vertical => BoxType::Horizontal,
35 }
36 }
37}
38impl Display for BoxType {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 match self {
41 BoxType::Horizontal => write!(f, "hbox"),
42 BoxType::Vertical => write!(f, "vbox"),
43 }
45 }
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub enum ToOrSpread<D: TeXDimen> {
51 None,
53 To(D),
55 Spread(D),
57}
58
59#[derive(Debug, Clone, PartialEq, Eq)]
61pub enum HBoxInfo<ET: EngineTypes> {
62 HBox {
64 scaled: ToOrSpread<ET::Dim>,
66 assigned_width: Option<ET::Dim>,
68 assigned_height: Option<ET::Dim>,
70 assigned_depth: Option<ET::Dim>,
72 moved_left: Option<ET::Dim>,
74 raised: Option<ET::Dim>,
76 computed_width: Once<ET::Dim>,
78 computed_height: Once<ET::Dim>,
80 computed_depth: Once<ET::Dim>,
82 },
83 ParLine {
85 spec: ParLineSpec<ET>,
87 ends_with_line_break: bool,
89 inner_height: ET::Dim,
91 inner_depth: ET::Dim,
93 },
94 HAlignRow,
96 HAlignCell {
98 to: Option<ET::Dim>,
100 computed_width: Once<ET::Dim>,
102 computed_height: Once<ET::Dim>,
104 computed_depth: Once<ET::Dim>,
106 spans: u8,
108 },
109 ParIndent(ET::Dim),
111}
112impl<ET: EngineTypes> Display for HBoxInfo<ET> {
113 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
114 use HBoxInfo::*;
115 match self {
116 HBox { .. } => write!(f, "hbox"),
117 ParLine { .. } => write!(f, "parline"),
118 ParIndent(_) => write!(f, "parindent"),
119 HAlignRow => write!(f, "halignrow"),
120 HAlignCell { .. } => write!(f, "haligncell"),
121 }
122 }
123}
124impl<ET: EngineTypes> HBoxInfo<ET> {
125 pub fn new_box(scaled: ToOrSpread<ET::Dim>) -> Self {
127 HBoxInfo::HBox {
128 scaled,
129 assigned_width: None,
130 assigned_height: None,
131 assigned_depth: None,
132 moved_left: None,
133 raised: None,
134 computed_width: Once::new(),
135 computed_height: Once::new(),
136 computed_depth: Once::new(),
137 }
138 }
139 pub fn to_hbox(&mut self) {
141 match self {
142 HBoxInfo::HBox { .. } => (),
143 HBoxInfo::ParLine { spec, .. } => {
144 *self = HBoxInfo::new_box(ToOrSpread::To(spec.target))
145 }
146 HBoxInfo::ParIndent(d) => *self = HBoxInfo::new_box(ToOrSpread::To(*d)),
147 HBoxInfo::HAlignRow => *self = HBoxInfo::new_box(ToOrSpread::None),
148 HBoxInfo::HAlignCell { to, .. } => {
149 *self = HBoxInfo::new_box(match to {
150 None => ToOrSpread::None,
151 Some(to) => ToOrSpread::To(*to),
152 })
153 }
154 }
155 }
156
157 pub fn new_cell(spans: u8) -> Self {
159 HBoxInfo::HAlignCell {
160 to: None,
161 computed_width: Once::new(),
162 computed_height: Once::new(),
163 computed_depth: Once::new(),
164 spans,
165 }
166 }
167 pub fn open_list(self, start: SourceRef<ET>) -> NodeList<ET> {
169 match self {
170 HBoxInfo::HBox { .. } => NodeList::Horizontal {
171 tp: HorizontalNodeListType::Box(self, start, BoxTarget::none()),
172 children: vec![],
173 },
174 HBoxInfo::ParLine { .. } => NodeList::Horizontal {
175 tp: HorizontalNodeListType::Paragraph(start),
176 children: vec![],
177 },
178 HBoxInfo::HAlignRow => NodeList::Horizontal {
179 tp: HorizontalNodeListType::HAlignRow(start),
180 children: vec![],
181 },
182 HBoxInfo::HAlignCell { .. } => NodeList::Horizontal {
183 tp: HorizontalNodeListType::HAlignCell(start, 0),
184 children: vec![],
185 },
186 HBoxInfo::ParIndent(_) => unreachable!(),
187 }
188 }
189
190 fn height_inner(v: &[HNode<ET>]) -> ET::Dim {
191 v.iter().map(|c| c.height()).max().unwrap_or_default()
192 }
193
194 fn depth_inner(v: &[HNode<ET>]) -> ET::Dim {
195 v.iter().map(|c| c.depth()).max().unwrap_or_default()
196 }
197
198 fn width_inner(v: &[HNode<ET>]) -> ET::Dim {
199 v.iter().map(|c| c.width()).sum()
200 }
201
202 fn get_height(&self, v: &[HNode<ET>]) -> ET::Dim {
203 match self {
204 HBoxInfo::HBox {
205 assigned_height,
206 computed_height,
207 ..
208 } => assigned_height
209 .unwrap_or_else(|| *computed_height.get_or_init(|| Self::height_inner(v))),
210 HBoxInfo::ParLine { inner_height, .. } => *inner_height,
211 HBoxInfo::HAlignRow => Self::height_inner(v),
212 HBoxInfo::HAlignCell { .. } => Self::height_inner(v),
213 HBoxInfo::ParIndent(_) => ET::Dim::default(),
214 }
215 }
216 fn get_width(&self, v: &[HNode<ET>]) -> ET::Dim {
217 match self {
218 HBoxInfo::HBox {
219 assigned_width,
220 computed_width,
221 ..
222 } => assigned_width
223 .unwrap_or_else(|| *computed_width.get_or_init(|| Self::width_inner(v))),
224 HBoxInfo::ParLine { spec, .. } => {
225 spec.leftskip.base + spec.rightskip.base + spec.target
226 }
227 HBoxInfo::HAlignRow => Self::width_inner(v),
228 HBoxInfo::HAlignCell {
229 to, computed_width, ..
230 } => to.unwrap_or_else(|| *computed_width.get_or_init(|| Self::width_inner(v))),
231 HBoxInfo::ParIndent(d) => *d,
232 }
233 }
234 fn get_depth(&self, v: &[HNode<ET>]) -> ET::Dim {
235 match self {
236 HBoxInfo::HBox {
237 assigned_depth,
238 computed_depth,
239 ..
240 } => assigned_depth
241 .unwrap_or_else(|| *computed_depth.get_or_init(|| Self::depth_inner(v))),
242 HBoxInfo::ParLine { inner_depth, .. } => *inner_depth,
243 HBoxInfo::HAlignRow => Self::depth_inner(v),
244 HBoxInfo::HAlignCell { .. } => Self::depth_inner(v),
245 HBoxInfo::ParIndent(_) => ET::Dim::default(),
246 }
247 }
248
249 pub fn raise(&mut self, d: ET::Dim) {
251 self.to_hbox();
252 match self {
253 HBoxInfo::HBox { ref mut raised, .. } => *raised = Some(d),
254 _ => unreachable!(),
255 }
256 }
257 pub fn move_left(&mut self, d: ET::Dim) {
259 self.to_hbox();
260 match self {
261 HBoxInfo::HBox {
262 ref mut moved_left, ..
263 } => *moved_left = Some(d),
264 _ => unreachable!(),
265 }
266 }
267}
268
269#[derive(Debug, Clone, PartialEq, Eq)]
271pub enum VBoxInfo<ET: EngineTypes> {
272 VBox {
274 scaled: ToOrSpread<ET::Dim>,
276 assigned_width: Option<ET::Dim>,
278 assigned_height: Option<ET::Dim>,
280 assigned_depth: Option<ET::Dim>,
282 moved_left: Option<ET::Dim>,
284 raised: Option<ET::Dim>,
286 computed_width: Once<ET::Dim>,
288 computed_height: Once<ET::Dim>,
290 computed_depth: Once<ET::Dim>,
292 },
293 VTop {
295 scaled: ToOrSpread<ET::Dim>,
297 assigned_width: Option<ET::Dim>,
299 assigned_height: Option<ET::Dim>,
301 assigned_depth: Option<ET::Dim>,
303 moved_left: Option<ET::Dim>,
305 raised: Option<ET::Dim>,
307 computed_width: Once<ET::Dim>,
309 computed_height: Once<ET::Dim>,
311 computed_depth: Once<ET::Dim>,
313 },
314 VAlignColumn,
316 VAlignCell {
318 to: Option<ET::Dim>,
320 spans: u8,
322 },
323}
324impl<ET: EngineTypes> Display for VBoxInfo<ET> {
325 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
326 use VBoxInfo::*;
327 match self {
328 VBox { .. } => write!(f, "vbox"),
329 VTop { .. } => write!(f, "vtop"),
330 VAlignColumn => write!(f, "valignrow"),
331 VAlignCell { .. } => write!(f, "valigncell"),
332 }
333 }
334}
335
336impl<ET: EngineTypes> VBoxInfo<ET> {
337 pub fn new_box(scaled: ToOrSpread<ET::Dim>) -> Self {
339 VBoxInfo::VBox {
340 scaled,
341 assigned_width: None,
342 assigned_height: None,
343 assigned_depth: None,
344 moved_left: None,
345 raised: None,
346 computed_width: Once::new(),
347 computed_height: Once::new(),
348 computed_depth: Once::new(),
349 }
350 }
351
352 pub fn to_vbox(&mut self) {
354 match self {
355 VBoxInfo::VTop { .. } | VBoxInfo::VBox { .. } => (),
356 VBoxInfo::VAlignColumn => *self = VBoxInfo::new_box(ToOrSpread::None),
357 VBoxInfo::VAlignCell { to, .. } => {
358 *self = VBoxInfo::new_box(match to {
359 None => ToOrSpread::None,
360 Some(d) => ToOrSpread::To(*d),
361 })
362 }
363 }
364 }
365
366 pub fn new_top(scaled: ToOrSpread<ET::Dim>) -> Self {
368 VBoxInfo::VTop {
369 scaled,
370 assigned_width: None,
371 assigned_height: None,
372 assigned_depth: None,
373 moved_left: None,
374 raised: None,
375 computed_width: Once::new(),
376 computed_height: Once::new(),
377 computed_depth: Once::new(),
378 }
379 }
380 pub fn open_list(self, start: SourceRef<ET>) -> NodeList<ET> {
382 match self {
383 VBoxInfo::VBox { .. } => NodeList::Vertical {
384 tp: VerticalNodeListType::Box(self, start, BoxTarget::none()),
385 children: vec![],
386 },
387 VBoxInfo::VTop { .. } => NodeList::Vertical {
388 tp: VerticalNodeListType::Box(self, start, BoxTarget::none()),
389 children: vec![],
390 },
391 VBoxInfo::VAlignColumn => NodeList::Vertical {
392 tp: VerticalNodeListType::VAlignColumn(start),
393 children: vec![],
394 },
395 VBoxInfo::VAlignCell { .. } => NodeList::Vertical {
396 tp: VerticalNodeListType::VAlignCell(start, 0),
397 children: vec![],
398 },
399 }
400 }
401 pub fn clone_for_split(&mut self) -> Self {
403 match self {
404 VBoxInfo::VBox {
405 scaled,
406 assigned_width,
407 assigned_height,
408 assigned_depth,
409 moved_left,
410 raised,
411 ..
412 } => {
413 *assigned_height = None;
414 *assigned_depth = None;
415 *scaled = ToOrSpread::None;
416 VBoxInfo::VBox {
417 scaled: ToOrSpread::None,
418 assigned_width: *assigned_width,
419 assigned_height: None,
420 assigned_depth: None,
421 moved_left: *moved_left,
422 raised: *raised,
423 computed_width: Once::new(),
424 computed_height: Once::new(),
425 computed_depth: Once::new(),
426 }
427 }
428 VBoxInfo::VTop {
429 scaled,
430 assigned_width,
431 assigned_height,
432 assigned_depth,
433 moved_left,
434 raised,
435 ..
436 } => {
437 *assigned_height = None;
438 *assigned_depth = None;
439 *scaled = ToOrSpread::None;
440 VBoxInfo::VBox {
441 scaled: ToOrSpread::None,
442 assigned_width: *assigned_width,
443 assigned_height: None,
444 assigned_depth: None,
445 moved_left: *moved_left,
446 raised: *raised,
447 computed_width: Once::new(),
448 computed_height: Once::new(),
449 computed_depth: Once::new(),
450 }
451 }
452 _ => unreachable!(),
453 }
454 }
455
456 fn height_inner(v: &[VNode<ET>]) -> ET::Dim {
457 v.iter().map(|c| c.height() + c.depth()).sum::<ET::Dim>() + -Self::depth_inner(v)
458 }
459
460 fn depth_inner(v: &[VNode<ET>]) -> ET::Dim {
461 for c in v.iter().rev() {
462 if !c.opaque() {
463 return c.depth();
464 }
465 }
466 ET::Dim::default()
467 }
468
469 fn width_inner(v: &[VNode<ET>]) -> ET::Dim {
470 v.iter().map(|c| c.width()).max().unwrap_or_default()
471 }
472
473 fn get_height(&self, v: &[VNode<ET>]) -> ET::Dim {
474 match self {
475 VBoxInfo::VAlignColumn => Self::height_inner(v),
476 VBoxInfo::VAlignCell { to, .. } => to.unwrap_or_else(|| Self::height_inner(v)),
477 VBoxInfo::VBox {
478 assigned_height,
479 computed_height,
480 ..
481 } => assigned_height
482 .unwrap_or_else(|| *computed_height.get_or_init(|| Self::height_inner(v))),
483 VBoxInfo::VTop {
484 assigned_height,
485 computed_height,
486 ..
487 } => assigned_height.unwrap_or_else(|| {
488 *computed_height.get_or_init(|| match v.first() {
489 Some(c @ VNode::Box(..)) => c.height(),
490 _ => ET::Dim::default(),
491 })
492 }),
493 }
494 }
495 fn get_width(&self, v: &[VNode<ET>]) -> ET::Dim {
496 match self {
497 VBoxInfo::VAlignColumn => Self::width_inner(v),
498 VBoxInfo::VAlignCell { .. } => Self::width_inner(v),
499 VBoxInfo::VBox {
500 assigned_width,
501 computed_width,
502 ..
503 } => assigned_width
504 .unwrap_or_else(|| *computed_width.get_or_init(|| Self::width_inner(v))),
505 VBoxInfo::VTop {
506 assigned_width,
507 computed_width,
508 ..
509 } => assigned_width
510 .unwrap_or_else(|| *computed_width.get_or_init(|| Self::width_inner(v))),
511 }
512 }
513 fn get_depth(&self, v: &[VNode<ET>]) -> ET::Dim {
514 match self {
515 VBoxInfo::VAlignColumn => Self::depth_inner(v),
516 VBoxInfo::VAlignCell { .. } => Self::depth_inner(v),
517 VBoxInfo::VBox {
518 assigned_depth,
519 computed_depth,
520 ..
521 } => assigned_depth
522 .unwrap_or_else(|| *computed_depth.get_or_init(|| Self::depth_inner(v))),
523 VBoxInfo::VTop {
524 assigned_depth,
525 computed_depth,
526 ..
527 } => assigned_depth.unwrap_or_else(|| {
528 *computed_depth.get_or_init(|| {
529 let x = match v.first() {
530 Some(c @ VNode::Box(..)) => c.height(),
531 _ => ET::Dim::default(),
532 };
533 let h = Self::height_inner(v);
534 let d = Self::depth_inner(v);
535 h + d - x
536 })
537 }),
538 }
539 }
540
541 pub fn raise(&mut self, d: ET::Dim) {
543 match self {
544 VBoxInfo::VBox { ref mut raised, .. } => *raised = Some(d),
545 VBoxInfo::VTop { ref mut raised, .. } => *raised = Some(d),
546 _ => {
547 self.to_vbox();
548 let VBoxInfo::VBox { raised, .. } = self else {
549 unreachable!()
550 };
551 *raised = Some(d)
552 }
553 }
554 }
555 pub fn move_left(&mut self, d: ET::Dim) {
557 match self {
558 VBoxInfo::VBox {
559 ref mut moved_left, ..
560 } => *moved_left = Some(d),
561 VBoxInfo::VTop {
562 ref mut moved_left, ..
563 } => *moved_left = Some(d),
564 _ => {
565 self.to_vbox();
566 let VBoxInfo::VBox { moved_left, .. } = self else {
567 unreachable!()
568 };
569 *moved_left = Some(d)
570 }
571 }
572 }
573}
574
575#[derive(Debug, Clone, PartialEq, Eq)]
577pub enum BoxInfo<ET: EngineTypes> {
578 H(HBoxInfo<ET>),
579 V(VBoxInfo<ET>),
580}
581impl<ET: EngineTypes> BoxInfo<ET> {
582 pub fn open_list(self, start: SourceRef<ET>) -> NodeList<ET> {
584 match self {
585 BoxInfo::H(h) => h.open_list(start),
586 BoxInfo::V(v) => v.open_list(start),
587 }
588 }
589 pub fn move_left(&mut self, d: ET::Dim) {
591 match self {
592 BoxInfo::H(h) => h.move_left(d),
593 BoxInfo::V(v) => v.move_left(d),
594 }
595 }
596 pub fn raise(&mut self, d: ET::Dim) {
598 match self {
599 BoxInfo::H(h) => h.raise(d),
600 BoxInfo::V(v) => v.raise(d),
601 }
602 }
603
604 pub fn assigned_height(&self) -> Option<ET::Dim> {
605 match self {
606 BoxInfo::H(h) => h.assigned_height(),
607 BoxInfo::V(v) => v.assigned_height(),
608 }
609 }
610 pub fn assigned_width(&self) -> Option<ET::Dim> {
611 match self {
612 BoxInfo::H(h) => h.assigned_width(),
613 BoxInfo::V(v) => v.assigned_width(),
614 }
615 }
616 pub fn assigned_depth(&self) -> Option<ET::Dim> {
617 match self {
618 BoxInfo::H(h) => h.assigned_depth(),
619 BoxInfo::V(v) => v.assigned_depth(),
620 }
621 }
622 pub fn computed_height(&self) -> Option<ET::Dim> {
623 match self {
624 BoxInfo::H(h) => h.computed_height(),
625 BoxInfo::V(v) => v.computed_height(),
626 }
627 }
628 pub fn computed_width(&self) -> Option<ET::Dim> {
629 match self {
630 BoxInfo::H(h) => h.computed_width(),
631 BoxInfo::V(v) => v.computed_width(),
632 }
633 }
634 pub fn computed_depth(&self) -> Option<ET::Dim> {
635 match self {
636 BoxInfo::H(h) => h.computed_depth(),
637 BoxInfo::V(v) => v.computed_depth(),
638 }
639 }
640 pub fn to_or_scaled(&self) -> Option<ToOrSpread<ET::Dim>> {
641 match self {
642 BoxInfo::H(HBoxInfo::HBox { scaled, .. }) => Some(*scaled),
643 BoxInfo::V(VBoxInfo::VBox { scaled, .. }) => Some(*scaled),
644 BoxInfo::V(VBoxInfo::VTop { scaled, .. }) => Some(*scaled),
645 _ => None,
646 }
647 }
648 pub fn raised(&self) -> Option<ET::Dim> {
649 match self {
650 BoxInfo::H(HBoxInfo::HBox { raised, .. }) => *raised,
651 BoxInfo::V(VBoxInfo::VBox { raised, .. }) => *raised,
652 BoxInfo::V(VBoxInfo::VTop { raised, .. }) => *raised,
653 _ => None,
654 }
655 }
656 pub fn moved_left(&self) -> Option<ET::Dim> {
657 match self {
658 BoxInfo::H(HBoxInfo::HBox { moved_left, .. }) => *moved_left,
659 BoxInfo::V(VBoxInfo::VBox { moved_left, .. }) => *moved_left,
660 BoxInfo::V(VBoxInfo::VTop { moved_left, .. }) => *moved_left,
661 _ => None,
662 }
663 }
664}
665impl<ET: EngineTypes> VBoxInfo<ET> {
666 pub fn assigned_height(&self) -> Option<ET::Dim> {
667 match self {
668 VBoxInfo::VBox {
669 assigned_height, ..
670 } => *assigned_height,
671 VBoxInfo::VTop {
672 assigned_height, ..
673 } => *assigned_height,
674 _ => None,
675 }
676 }
677 pub fn assigned_width(&self) -> Option<ET::Dim> {
678 match self {
679 VBoxInfo::VBox { assigned_width, .. } => *assigned_width,
680 VBoxInfo::VTop { assigned_width, .. } => *assigned_width,
681 _ => None,
682 }
683 }
684 pub fn assigned_depth(&self) -> Option<ET::Dim> {
685 match self {
686 VBoxInfo::VBox { assigned_depth, .. } => *assigned_depth,
687 VBoxInfo::VTop { assigned_depth, .. } => *assigned_depth,
688 _ => None,
689 }
690 }
691 pub fn computed_height(&self) -> Option<ET::Dim> {
692 match self {
693 VBoxInfo::VBox {
694 computed_height, ..
695 } => computed_height.get().copied(),
696 VBoxInfo::VTop {
697 computed_height, ..
698 } => computed_height.get().copied(),
699 _ => None,
700 }
701 }
702 pub fn computed_width(&self) -> Option<ET::Dim> {
703 match self {
704 VBoxInfo::VBox { computed_width, .. } => computed_width.get().copied(),
705 VBoxInfo::VTop { computed_width, .. } => computed_width.get().copied(),
706 _ => None,
707 }
708 }
709 pub fn computed_depth(&self) -> Option<ET::Dim> {
710 match self {
711 VBoxInfo::VBox { computed_depth, .. } => computed_depth.get().copied(),
712 VBoxInfo::VTop { computed_depth, .. } => computed_depth.get().copied(),
713 _ => None,
714 }
715 }
716 pub fn raised(&self) -> Option<ET::Dim> {
717 match self {
718 VBoxInfo::VBox { raised, .. } => *raised,
719 VBoxInfo::VTop { raised, .. } => *raised,
720 _ => None,
721 }
722 }
723 pub fn moved_left(&self) -> Option<ET::Dim> {
724 match self {
725 VBoxInfo::VBox { moved_left, .. } => *moved_left,
726 VBoxInfo::VTop { moved_left, .. } => *moved_left,
727 _ => None,
728 }
729 }
730 pub fn to_or_scaled(&self) -> Option<ToOrSpread<ET::Dim>> {
731 match self {
732 VBoxInfo::VBox { scaled, .. } => Some(*scaled),
733 VBoxInfo::VTop { scaled, .. } => Some(*scaled),
734 _ => None,
735 }
736 }
737}
738impl<ET: EngineTypes> HBoxInfo<ET> {
739 pub fn assigned_height(&self) -> Option<ET::Dim> {
740 match self {
741 HBoxInfo::HBox {
742 assigned_height, ..
743 } => *assigned_height,
744 _ => None,
745 }
746 }
747 pub fn assigned_width(&self) -> Option<ET::Dim> {
748 match self {
749 HBoxInfo::HBox { assigned_width, .. } => *assigned_width,
750 _ => None,
751 }
752 }
753 pub fn assigned_depth(&self) -> Option<ET::Dim> {
754 match self {
755 HBoxInfo::HBox { assigned_depth, .. } => *assigned_depth,
756 _ => None,
757 }
758 }
759 pub fn computed_height(&self) -> Option<ET::Dim> {
760 match self {
761 HBoxInfo::HBox {
762 computed_height, ..
763 } => computed_height.get().copied(),
764 _ => None,
765 }
766 }
767 pub fn computed_width(&self) -> Option<ET::Dim> {
768 match self {
769 HBoxInfo::HBox { computed_width, .. } => computed_width.get().copied(),
770 _ => None,
771 }
772 }
773 pub fn computed_depth(&self) -> Option<ET::Dim> {
774 match self {
775 HBoxInfo::HBox { computed_depth, .. } => computed_depth.get().copied(),
776 _ => None,
777 }
778 }
779 pub fn raised(&self) -> Option<ET::Dim> {
780 match self {
781 HBoxInfo::HBox { raised, .. } => *raised,
782 _ => None,
783 }
784 }
785 pub fn moved_left(&self) -> Option<ET::Dim> {
786 match self {
787 HBoxInfo::HBox { moved_left, .. } => *moved_left,
788 _ => None,
789 }
790 }
791 pub fn to_or_scaled(&self) -> Option<ToOrSpread<ET::Dim>> {
792 match self {
793 HBoxInfo::HBox { scaled, .. } => Some(*scaled),
794 _ => None,
795 }
796 }
797}
798
799#[derive(Debug, Clone)]
802pub enum TeXBox<ET: EngineTypes> {
803 V {
805 info: VBoxInfo<ET>,
807 children: Box<[VNode<ET>]>,
809 start: SourceRef<ET>,
811 end: SourceRef<ET>,
813 },
814 H {
816 info: HBoxInfo<ET>,
818 children: Box<[HNode<ET>]>,
820 start: SourceRef<ET>,
822 end: SourceRef<ET>,
824 preskip: Option<Skip<ET::Dim>>,
826 },
827}
828
829impl<ET: EngineTypes> TeXBox<ET> {
830 pub fn to_math(self) -> MathNode<ET, UnresolvedMathFontStyle<ET>> {
831 MathNode::Atom(MathAtom {
832 nucleus: MathNucleus::Simple {
833 kernel: MathKernel::Box(self),
834 limits: None,
835 cls: MathClass::Ord,
836 },
837 sub: None,
838 sup: None,
839 })
840 }
841 pub fn is_empty(&self) -> bool {
843 match self {
844 TeXBox::H { children, .. } => children.is_empty(),
845 TeXBox::V { children, .. } => children.is_empty(),
846 }
847 }
848 pub fn assign_height(&mut self, h: ET::Dim) {
850 match self {
851 TeXBox::H {
852 info:
853 HBoxInfo::HBox {
854 ref mut assigned_height,
855 ..
856 },
857 ..
858 } => *assigned_height = Some(h),
859 TeXBox::V {
860 info:
861 VBoxInfo::VBox {
862 ref mut assigned_height,
863 ..
864 },
865 ..
866 } => *assigned_height = Some(h),
867 TeXBox::V {
868 info:
869 VBoxInfo::VTop {
870 ref mut assigned_height,
871 ..
872 },
873 ..
874 } => *assigned_height = Some(h),
875 _ => (),
876 }
877 }
878 pub fn assigned_height(&self) -> Option<ET::Dim> {
880 match self {
881 TeXBox::H {
882 info: HBoxInfo::HBox {
883 assigned_height, ..
884 },
885 ..
886 } => *assigned_height,
887 TeXBox::V {
888 info: VBoxInfo::VBox {
889 assigned_height, ..
890 },
891 ..
892 } => *assigned_height,
893 TeXBox::V {
894 info: VBoxInfo::VTop {
895 assigned_height, ..
896 },
897 ..
898 } => *assigned_height,
899 _ => None,
900 }
901 }
902 pub fn assign_width(&mut self, w: ET::Dim) {
904 match self {
905 TeXBox::H {
906 info:
907 HBoxInfo::HBox {
908 ref mut assigned_width,
909 ..
910 },
911 ..
912 } => *assigned_width = Some(w),
913 TeXBox::V {
914 info:
915 VBoxInfo::VBox {
916 ref mut assigned_width,
917 ..
918 },
919 ..
920 } => *assigned_width = Some(w),
921 TeXBox::V {
922 info:
923 VBoxInfo::VTop {
924 ref mut assigned_width,
925 ..
926 },
927 ..
928 } => *assigned_width = Some(w),
929 _ => (),
930 }
931 }
932 pub fn assigned_width(&self) -> Option<ET::Dim> {
934 match self {
935 TeXBox::H {
936 info: HBoxInfo::HBox { assigned_width, .. },
937 ..
938 } => *assigned_width,
939 TeXBox::V {
940 info: VBoxInfo::VBox { assigned_width, .. },
941 ..
942 } => *assigned_width,
943 TeXBox::V {
944 info: VBoxInfo::VTop { assigned_width, .. },
945 ..
946 } => *assigned_width,
947 _ => None,
948 }
949 }
950 pub fn assign_depth(&mut self, d: ET::Dim) {
952 match self {
953 TeXBox::H {
954 info:
955 HBoxInfo::HBox {
956 ref mut assigned_depth,
957 ..
958 },
959 ..
960 } => *assigned_depth = Some(d),
961 TeXBox::V {
962 info:
963 VBoxInfo::VBox {
964 ref mut assigned_depth,
965 ..
966 },
967 ..
968 } => *assigned_depth = Some(d),
969 TeXBox::V {
970 info:
971 VBoxInfo::VTop {
972 ref mut assigned_depth,
973 ..
974 },
975 ..
976 } => *assigned_depth = Some(d),
977 _ => (),
978 }
979 }
980 pub fn assigned_depth(&self) -> Option<ET::Dim> {
982 match self {
983 TeXBox::H {
984 info: HBoxInfo::HBox { assigned_depth, .. },
985 ..
986 } => *assigned_depth,
987 TeXBox::V {
988 info: VBoxInfo::VBox { assigned_depth, .. },
989 ..
990 } => *assigned_depth,
991 TeXBox::V {
992 info: VBoxInfo::VTop { assigned_depth, .. },
993 ..
994 } => *assigned_depth,
995 _ => None,
996 }
997 }
998 pub fn to_or_scaled(&self) -> ToOrSpread<ET::Dim> {
1000 match self {
1001 TeXBox::H {
1002 info: HBoxInfo::HBox { scaled, .. },
1003 ..
1004 } => *scaled,
1005 TeXBox::V {
1006 info: VBoxInfo::VBox { scaled, .. },
1007 ..
1008 } => *scaled,
1009 TeXBox::V {
1010 info: VBoxInfo::VTop { scaled, .. },
1011 ..
1012 } => *scaled,
1013 _ => ToOrSpread::None,
1014 }
1015 }
1016}
1017
1018impl<ET: EngineTypes> NodeTrait<ET> for TeXBox<ET> {
1019 fn display_fmt(&self, indent: usize, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1020 display_do_indent(indent, f)?;
1021 match self {
1022 TeXBox::H { info, children, .. } => {
1023 write!(f, "<hbox:{}>", info)?;
1024 for c in children.iter() {
1025 c.display_fmt(indent + 2, f)?;
1026 }
1027 display_do_indent(indent, f)?;
1028 write!(f, "</hbox:{}>", info)
1029 }
1030 TeXBox::V { info, children, .. } => {
1031 write!(f, "<vbox:{}>", info)?;
1032 for c in children.iter() {
1033 c.display_fmt(indent + 2, f)?;
1034 }
1035 display_do_indent(indent, f)?;
1036 write!(f, "</vbox:{}>", info)
1037 }
1038 }
1039 }
1040
1041 fn height(&self) -> ET::Dim {
1042 match self {
1043 TeXBox::H {
1044 info,
1045 children,
1046 preskip,
1047 ..
1048 } => info.get_height(children) + preskip.map(|s| s.base).unwrap_or_default(),
1049 TeXBox::V { info, children, .. } => info.get_height(children),
1050 }
1051 }
1052
1053 fn width(&self) -> ET::Dim {
1054 match self {
1055 TeXBox::H { info, children, .. } => info.get_width(children),
1056 TeXBox::V { info, children, .. } => info.get_width(children),
1057 }
1058 }
1059
1060 fn depth(&self) -> ET::Dim {
1061 match self {
1062 TeXBox::H { info, children, .. } => info.get_depth(children),
1063 TeXBox::V { info, children, .. } => info.get_depth(children),
1064 }
1065 }
1066 fn nodetype(&self) -> NodeType {
1067 match self {
1068 TeXBox::H { .. } => NodeType::HList,
1069 TeXBox::V { .. } => NodeType::VList,
1070 }
1071 }
1072 fn sourceref(&self) -> Option<(&SourceRef<ET>, &SourceRef<ET>)> {
1073 match self {
1074 TeXBox::H { start, end, .. } => Some((start, end)),
1075 TeXBox::V { start, end, .. } => Some((start, end)),
1076 }
1077 }
1078}