1pub(crate) mod annotations;
2pub(crate) mod html;
3pub(crate) mod nodes;
4pub(crate) mod state;
5pub(crate) mod utils;
6
7use crate::engine::nodes::{LineSkip, RusTeXNode};
8use crate::engine::{Refs, Res, SRef, Types};
9use crate::shipout::state::{
10 Common, HLike, Math, ModeKind, Row, SVG, Shipout, ShipoutNodeH, ShipoutNodeM, ShipoutNodeT,
11 ShipoutNodeTable, ShipoutNodeV, ShipoutState, VLike,
12};
13use crate::shipout::utils::{HNodes, MNode, MNodes, VNodes};
14use crate::utils::{Flex, Margin};
15use tex_engine::engine::stomach::methods::ParLineSpec;
16use tex_engine::pdflatex::nodes::{PDFDest, PDFNode};
17use tex_engine::tex::nodes::NodeTrait;
18use tex_engine::tex::nodes::boxes::{HBoxInfo, TeXBox, ToOrSpread, VBoxInfo};
19use tex_engine::tex::nodes::horizontal::HNode;
20use tex_engine::tex::nodes::math::{
21 MathAtom, MathFontStyle, MathGroup, MathKernel, MathNode, MathNucleus, MathStyle, MathStyleType,
22};
23use tex_engine::tex::nodes::vertical::VNode;
24use tex_engine::tex::numerics::{Dim32, Skip};
25use tex_engine::utils::errors::TeXError;
26pub fn shipout(engine: Refs, n: VNode<Types>) -> Res<()> {
44 match n {
46 VNode::Box(TeXBox::V { children, .. }) => {
47 let children = get_page_inner(children.into_vec());
48 ShipoutState::split_state(engine, |state| state.do_vlist(&mut children.into()))
53 .map_err(|e| TeXError::General(format!("Not allowed in V-Mode: {e:?}")))?;
54 }
60 _ => unreachable!(),
61 }
62 Ok(())
63}
64
65impl<Mode: VLike> Shipout<'_, '_, Mode> {
66 fn do_vlist(&mut self, children: &mut VNodes) -> Result<(), Option<VNode<Types>>> {
67 while let Some(c) = children.next() {
69 match c {
70 VNode::Custom(RusTeXNode::PDFNode(
71 PDFNode::PDFOutline(_)
72 | PDFNode::PDFPageAttr(_)
73 | PDFNode::PDFPagesAttr(_)
74 | PDFNode::PDFCatalog(_)
75 | PDFNode::PDFSave
76 | PDFNode::PDFAnnot(_)
77 | PDFNode::PDFLiteral(_)
78 | PDFNode::XForm(_)
79 | PDFNode::Obj(_),
80 ))
81 | VNode::Penalty(_)
82 | VNode::Mark(..)
83 | VNode::Custom(
84 RusTeXNode::PageBegin | RusTeXNode::PageEnd | RusTeXNode::HAlignEnd,
85 ) => (),
86 VNode::Custom(RusTeXNode::PGFEscape(bx)) => children.prefix(vec![VNode::Box(bx)]), VNode::Custom(RusTeXNode::PDFNode(PDFNode::Color(act))) => self.do_color(act),
88 VNode::Custom(RusTeXNode::FontChange(font, global)) => self.open_font(font, global),
89 VNode::Custom(RusTeXNode::FontChangeEnd) => self.close_font(),
90 VNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFStartLink(link))) => {
91 self.open_link(link)
92 }
93 VNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFEndLink)) => self.close_link(),
94 VNode::Custom(RusTeXNode::AnnotBegin {
95 start,
96 attrs,
97 styles,
98 classes,
99 tag,
100 }) => self.open_annot(
101 start,
102 attrs.into(),
103 styles.into(),
104 classes.into_iter().map(String::into).collect(),
105 tag,
106 ),
107 VNode::Custom(RusTeXNode::AnnotEnd(end)) => self.close_annot(end),
108 VNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFMatrix {
109 scale,
110 rotate,
111 skewx,
112 skewy,
113 })) => self.open_matrix(scale, rotate, skewx, skewy),
114 VNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFRestore)) => self.close_matrix(),
115 VNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFDest(PDFDest { id, .. }))) => {
116 self.push(Common::PDFDest(id).into())
117 }
118 VNode::Whatsit(wi) => wi.call(self.engine).map_err(|_| None)?,
119 VNode::Custom(RusTeXNode::PGFGBegin { .. } | RusTeXNode::PGFGEnd) => (), VNode::Custom(RusTeXNode::PGFSvg {
121 bx,
122 minx,
123 miny,
124 maxx,
125 maxy,
126 }) => {
127 if let TeXBox::H {
128 children,
129 start,
130 end,
131 ..
132 } = bx
133 {
134 self.in_svg(start, end, minx.0, miny.0, maxx.0, maxy.0, |state| {
135 state.do_svglist(&mut children.into()).map_err(|_| None)
136 })
137 .map_err(|_| None)?
138 } else {
139 unreachable!()
140 }
141 }
142 VNode::Leaders(_) => (), VNode::Custom(RusTeXNode::Literal(s)) => self.push(Common::Literal(s).into()),
144
145 VNode::VKern(d) => self.skipv(d.into()),
147 VNode::VSkip(s) => self.skipv(s.into()),
148 VNode::VFil => self.skipv(Margin::fil()),
149 VNode::VFill => self.skipv(Margin::fill()),
150 VNode::Vss => self.skipv(Margin::ss()),
151 VNode::VFilneg => self.skipv(Margin {
152 base: 0,
153 stretch: Flex::Fil(-1),
154 shrink: Flex::Fixed(0),
155 }),
156 VNode::Custom(RusTeXNode::ParagraphBegin {
157 specs,
158 start,
159 end,
160 lineskip,
161 parskip,
162 }) => self.do_par(children, specs, start, end, lineskip, parskip)?,
163 VNode::Custom(RusTeXNode::HAlignBegin { lineskip }) => {
165 self.do_halign(children, lineskip)?
166 }
167 VNode::Box(tb) => {
182 let _ = tb.height();
183 let _ = tb.width();
184 let _ = tb.depth();
185 match tb {
186 TeXBox::V {
187 info:
188 VBoxInfo::VBox {
189 scaled: ToOrSpread::None,
190 assigned_width: None,
191 assigned_height: None,
192 assigned_depth: None,
193 moved_left: None,
194 raised: None,
195 ..
196 },
197 children: next,
198 ..
199 } => {
200 children.prefix(next.into());
201 }
202 TeXBox::V {
203 info,
204 children,
205 start,
206 end,
207 } if matches!(info, VBoxInfo::VBox { .. } | VBoxInfo::VTop { .. }) => self
208 .in_v(start, end, info, |state| {
209 state.do_vlist(&mut children.into())
210 })?,
211 TeXBox::H {
212 info,
213 children,
214 start,
215 end,
216 preskip,
217 } if matches!(info, HBoxInfo::HBox { .. }) => self
218 .in_h(start, end, info, preskip, |state| {
219 state.do_hlist(&mut children.into())
220 })
221 .map_err(|_| None)?,
222 TeXBox::H {
223 info: HBoxInfo::HAlignRow,
224 children,
225 start,
226 end,
227 ..
228 } => {
229 let mut redos = Vec::new();
230 let mut done = false;
231 while let Some(mut c) = self.nodes.pop() {
232 match &mut c {
233 ShipoutNodeV::HAlign {
234 children: chs,
235 num_cols,
236 uses_color,
237 uses_font,
238 ..
239 } => {
240 chs.push(ShipoutNodeTable::NoAlign {
241 uses_font: redos
242 .iter()
243 .any(|c: &ShipoutNodeV| c.uses_previous_font()),
244 uses_color: redos
245 .iter()
246 .any(|c: &ShipoutNodeV| c.uses_previous_color()),
247 children: std::mem::take(&mut redos),
248 });
249 self.reopen_halign(
250 start,
251 end,
252 chs,
253 num_cols,
254 uses_color,
255 uses_font,
256 |state| state.do_row(children),
257 )
258 .map_err(|_| None)?;
259 done = true;
260 break;
261 }
262 _ => redos.push(c),
263 }
264 }
265 if !done {
266 for r in redos.into_iter().rev() {
267 self.push(r)
268 }
269 }
270 }
272 _ => todo!("{tb:?}"),
273 }
274 }
275 VNode::HRule {
276 width,
277 height,
278 depth,
279 ..
280 } => self.push(ShipoutNodeV::HRule {
281 width,
282 height,
283 depth,
284 }),
285 VNode::Custom(RusTeXNode::PDFNode(PDFNode::XImage(_))) => todo!(),
286
287 _ => todo!("{c:?}"),
288 }
289 }
290 Ok(())
291 }
292
293 fn do_par(
294 &mut self,
295 children: &mut VNodes,
296 specs: Vec<ParLineSpec<Types>>,
297 start: SRef,
298 end: SRef,
299 lineskip: LineSkip,
300 parskip: Skip<Dim32>,
301 ) -> Result<(), Option<VNode<Types>>> {
302 let ret = self.in_par(specs, start, end, lineskip, parskip, |state| {
304 let mut later = Vec::new();
305 let mut emergency_break = false;
306 let mut is_empty = true;
307 while let Some(c) = children.next() {
308 match c {
309 VNode::VSkip(_)
310 | VNode::VFil
311 | VNode::VFill
312 | VNode::VFilneg
313 | VNode::Vss
314 | VNode::Mark(..)
315 | VNode::VKern(_) => (),
316 VNode::Custom(RusTeXNode::ParagraphEnd) if is_empty => emergency_break = true,
317 VNode::Custom(RusTeXNode::ParagraphEnd) => return Ok(later),
318 VNode::Box(TeXBox::H {
319 info:
320 HBoxInfo::ParLine {
321 ends_with_line_break,
322 ..
323 },
324 children,
325 ..
326 }) => {
327 is_empty = false;
328 state.do_hlist(&mut children.into()).map_err(|_| None)?;
329 if ends_with_line_break {
330 state.push(ShipoutNodeH::LineBreak)
331 }
332 }
333 VNode::Box(TeXBox::H {
334 info:
335 HBoxInfo::HBox {
336 moved_left: None,
337 raised: None,
338 ..
339 },
340 children,
341 ..
342 }) if emergency_break => {
343 is_empty = false;
344 state.do_hlist(&mut children.into()).map_err(|_| None)?
345 }
346 _ => {
347 later.push(c);
348 if emergency_break {
349 return Ok(later);
350 }
351 }
352 }
353 }
354 Ok(later)
355 })?;
356 children.prefix(ret);
357 Ok(())
358 }
359
360 fn do_halign(
361 &mut self,
362 children: &mut VNodes,
363 lineskip: LineSkip,
364 ) -> Result<(), Option<VNode<Types>>> {
365 self.in_halign(lineskip, move |state| {
366 while let Some(row) = children.next() {
367 match row {
368 VNode::Custom(RusTeXNode::HAlignEnd) => break,
369 VNode::Box(TeXBox::H {
370 info: HBoxInfo::HAlignRow,
371 children,
372 start,
373 end,
374 ..
375 }) => {
376 state
377 .in_row(start, end, |state| state.do_row(children))
378 .map_err(|_| None)?;
379 }
380 VNode::Box(
381 b @ TeXBox::H {
382 info: HBoxInfo::HAlignCell { .. },
383 start,
384 end,
385 ..
386 },
387 ) => {
388 let c = vec![HNode::Box(b)].into();
389 state
390 .in_row(start, end, |state| state.do_row(c))
391 .map_err(|_| None)?;
392 }
393 v => {
394 let children = vec![v];
395 match state.in_noalign(|s| s.do_vlist(&mut children.into())) {
396 Ok(()) => (),
397 Err(Some(VNode::Custom(RusTeXNode::HAlignEnd))) => break,
398 Err(Some(VNode::Box(TeXBox::H {
399 info: HBoxInfo::HAlignRow,
400 children,
401 start,
402 end,
403 ..
404 }))) => {
405 state
406 .in_row(start, end, |state| state.do_row(children))
407 .map_err(|_| None)?;
408 }
409 o => return o,
410 }
411 }
412 }
413 }
414 Ok(())
415 })
416 }
417}
418
419impl Shipout<'_, '_, Row> {
420 fn do_row(&mut self, children: Box<[HNode<Types>]>) -> Result<(), Option<HNode<Types>>> {
421 for c in children {
422 match c {
423 HNode::Box(TeXBox::H {
424 info: HBoxInfo::HAlignCell { spans, .. },
425 children,
426 start,
427 end,
428 ..
429 }) => self
430 .in_cell(
431 start,
432 end,
433 children
434 .iter()
435 .max_by_key(|e| e.height().0 + e.depth().0)
436 .map(|e| e.height() + e.depth())
437 .unwrap_or_default(),
438 spans,
439 |state| state.do_hlist(&mut children.into()),
440 )
441 .map_err(|_| None)?,
442 _ => todo!(),
443 }
444 }
445 Ok(())
446 }
447}
448
449impl<Mode: HLike> Shipout<'_, '_, Mode> {
450 fn do_hlist(&mut self, children: &mut HNodes) -> Result<(), Option<HNode<Types>>> {
451 while let Some(c) = children.next() {
452 match c {
453 HNode::Custom(RusTeXNode::PDFNode(
454 PDFNode::PDFOutline(_)
455 | PDFNode::PDFPageAttr(_)
456 | PDFNode::PDFPagesAttr(_)
457 | PDFNode::PDFCatalog(_)
458 | PDFNode::PDFSave
459 | PDFNode::PDFAnnot(_)
460 | PDFNode::PDFLiteral(_)
461 | PDFNode::XForm(_)
462 | PDFNode::Obj(_),
463 ))
464 | HNode::Penalty(_)
465 | HNode::Mark(..)
466 | HNode::Custom(
467 RusTeXNode::PageBegin | RusTeXNode::PageEnd | RusTeXNode::HAlignEnd,
468 ) => (),
469 HNode::Custom(RusTeXNode::PGFEscape(bx)) => children.prefix(vec![HNode::Box(bx)]),
470 HNode::Custom(RusTeXNode::PDFNode(PDFNode::Color(act))) => self.do_color(act),
471 HNode::Custom(RusTeXNode::FontChange(font, global)) => self.open_font(font, global),
472 HNode::Custom(RusTeXNode::FontChangeEnd) => self.close_font(),
473 HNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFStartLink(link))) => {
474 self.open_link(link)
475 }
476 HNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFEndLink)) => self.close_link(),
477 HNode::Custom(RusTeXNode::AnnotBegin {
478 start,
479 attrs,
480 styles,
481 classes,
482 tag,
483 }) => self.open_annot(
484 start,
485 attrs.into(),
486 styles.into(),
487 classes.into_iter().map(String::into).collect(),
488 tag,
489 ),
490 HNode::Custom(RusTeXNode::AnnotEnd(end)) => self.close_annot(end),
491 HNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFMatrix {
492 scale,
493 rotate,
494 skewx,
495 skewy,
496 })) => self.open_matrix(scale, rotate, skewx, skewy),
497 HNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFRestore)) => self.close_matrix(),
498 HNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFDest(PDFDest { id, .. }))) => {
499 self.push(Common::PDFDest(id).into())
500 }
501 HNode::Whatsit(wi) => wi.call(self.engine).map_err(|_| None)?,
502 HNode::Custom(RusTeXNode::Literal(s)) => self.push(Common::Literal(s).into()),
503 HNode::Custom(RusTeXNode::PGFGBegin { .. } | RusTeXNode::PGFGEnd) => (), HNode::Custom(RusTeXNode::PGFSvg {
505 bx,
506 minx,
507 miny,
508 maxx,
509 maxy,
510 }) => {
511 if let TeXBox::H {
512 children,
513 start,
514 end,
515 ..
516 } = bx
517 {
518 self.in_svg(start, end, minx.0, miny.0, maxx.0, maxy.0, |state| {
519 state.do_svglist(&mut children.into()).map_err(|_| None)
520 })
521 .map_err(|_| None)?
522 } else {
523 unreachable!()
524 }
525 }
526 HNode::Leaders(_) => (), HNode::HSkip(sk) => self.skiph(sk.into()),
529 HNode::HKern(kn) => self.skiph(kn.into()),
530 HNode::HFil => self.skiph(Margin::fil()),
531 HNode::HFill => self.skiph(Margin::fill()),
532 HNode::Hss => self.skiph(Margin::ss()),
533 HNode::HFilneg => self.skiph(Margin {
534 base: 0,
535 stretch: Flex::Fil(-1),
536 shrink: Flex::Fixed(0),
537 }),
538
539 HNode::Box(bx) => {
540 let _ = bx.height();
541 let _ = bx.width();
542 let _ = bx.depth();
543 match bx {
544 TeXBox::V {
545 info,
546 children,
547 start,
548 end,
549 } if matches!(info, VBoxInfo::VBox { .. } | VBoxInfo::VTop { .. }) => self
550 .in_v(start, end, info, |state| {
551 state.do_vlist(&mut children.into())
552 })
553 .map_err(|_| None)?,
554 TeXBox::H {
555 info: HBoxInfo::ParIndent(d),
556 ..
557 } => self.indent(d.0),
558 TeXBox::H {
559 info:
560 HBoxInfo::HBox {
561 scaled: ToOrSpread::None,
562 assigned_width: None,
563 assigned_height: None,
564 assigned_depth: None,
565 moved_left: None,
566 raised: None,
567 ..
568 },
569 children: next,
570 ..
571 } if Mode::kind() == ModeKind::H => {
572 children.prefix(next.into());
573 }
574 TeXBox::H {
575 info,
576 children,
577 start,
578 end,
579 preskip,
580 } if matches!(info, HBoxInfo::HBox { .. }) => self
581 .in_h(start, end, info, preskip, |state| {
582 state.do_hlist(&mut children.into())
583 })
584 .map_err(|_| None)?,
585 TeXBox::H {
586 info: mut info @ HBoxInfo::ParLine { .. },
587 children,
588 start,
589 end,
590 ..
591 } => {
592 info.to_hbox();
593 self.in_h(start, end, info, None, |state| {
594 state.do_hlist(&mut children.into())
595 })
596 .map_err(|_| None)?
597 }
598 _ => todo!("{bx:?}"),
599 }
600 }
601 HNode::MathGroup(MathGroup {
602 start,
603 end,
604 display,
605 children,
606 ..
607 }) => self
608 .in_math(
609 start,
610 end,
611 display.map(|(a, b)| (a.into(), b.into())).into(),
612 |state| state.do_mathlist(&mut children.into()),
613 )
614 .map_err(|_| None)?,
615
616 HNode::VRule {
617 width,
618 height,
619 depth,
620 ..
621 } => self.push(ShipoutNodeH::VRule {
622 width,
623 height,
624 depth,
625 }),
626 HNode::Char { char, font } => {
627 let r =
628 ShipoutNodeH::char(char, font, self.engine, &mut self.top_state.font_data);
629 self.push(r)
630 }
631 HNode::Space => self.push(ShipoutNodeH::Space),
632 HNode::Custom(RusTeXNode::PDFNode(PDFNode::XImage(img))) => {
633 self.push(ShipoutNodeH::Img(img))
634 }
635 HNode::Accent { accent, char, font } => {
636 let r = ShipoutNodeH::accent(
637 char,
638 accent,
639 font,
640 self.engine,
641 &mut self.top_state.font_data,
642 );
643 self.push(r)
644 }
645 _ => todo!("{c:?}"),
646 }
647 }
648 Ok(())
649 }
650}
651
652impl Shipout<'_, '_, Math> {
653 fn do_mathlist(
654 &mut self,
655 children: &mut MNodes,
656 ) -> Result<(), Option<MathNode<Types, MathFontStyle<Types>>>> {
657 while let Some(c) = children.next() {
658 match c {
659 MNode::Custom(RusTeXNode::PDFNode(
660 PDFNode::PDFOutline(_)
661 | PDFNode::PDFPageAttr(_)
662 | PDFNode::PDFPagesAttr(_)
663 | PDFNode::PDFCatalog(_)
664 | PDFNode::PDFSave
665 | PDFNode::PDFAnnot(_)
666 | PDFNode::PDFLiteral(_)
667 | PDFNode::XForm(_)
668 | PDFNode::Obj(_),
669 ))
670 | MNode::Penalty(_)
671 | MNode::Mark(..)
672 | MNode::Custom(
673 RusTeXNode::PageBegin | RusTeXNode::PageEnd | RusTeXNode::HAlignEnd,
674 ) => (),
675 MNode::Custom(RusTeXNode::PGFEscape(_bx)) => todo!(), MNode::Custom(RusTeXNode::PDFNode(PDFNode::Color(act))) => self.do_color(act),
677 MNode::Custom(RusTeXNode::FontChange(font, global)) => self.open_font(font, global),
678 MNode::Custom(RusTeXNode::FontChangeEnd) => self.close_font(),
679 MNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFStartLink(link))) => {
680 self.open_link(link)
681 }
682 MNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFEndLink)) => self.close_link(),
683 MNode::Custom(RusTeXNode::AnnotBegin {
684 start,
685 attrs,
686 styles,
687 classes,
688 tag,
689 }) => self.open_annot(
690 start,
691 attrs.into(),
692 styles.into(),
693 classes.into_iter().map(String::into).collect(),
694 tag,
695 ),
696 MNode::Custom(RusTeXNode::AnnotEnd(end)) => self.close_annot(end),
697 MNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFMatrix {
698 scale,
699 rotate,
700 skewx,
701 skewy,
702 })) => self.open_matrix(scale, rotate, skewx, skewy),
703 MNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFRestore)) => self.close_matrix(),
704 MNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFDest(PDFDest { id, .. }))) => {
705 self.push(Common::PDFDest(id).into())
706 }
707 MNode::Whatsit(wi) => wi.call(self.engine).map_err(|_| None)?,
708 MNode::Custom(RusTeXNode::Literal(s)) => self.push(Common::Literal(s).into()),
709 MNode::Custom(RusTeXNode::PDFNode(PDFNode::XImage(img))) => {
710 self.push(ShipoutNodeM::Img(img))
711 }
712 MNode::Custom(RusTeXNode::PGFGBegin { .. } | RusTeXNode::PGFGEnd) => todo!(),
713 MNode::Space => self.push(ShipoutNodeM::Space),
714 MNode::MSkip { skip, .. } => self.push(ShipoutNodeM::MSkip {
715 base: skip.base.0,
716 mu: true,
717 }),
718 MNode::MKern { kern, .. } => self.push(ShipoutNodeM::MSkip {
719 base: kern.0,
720 mu: true,
721 }),
722 MNode::HSkip(skip) => self.push(ShipoutNodeM::MSkip {
723 base: skip.base.0,
724 mu: false,
725 }),
726 MNode::HKern(kern) => self.push(ShipoutNodeM::MSkip {
727 base: kern.0,
728 mu: false,
729 }),
730 MNode::HFil | MNode::HFill | MNode::Hss | MNode::HFilneg => (), MNode::Choice(ls) => children.prefix(ls.0.into_vec()),
732 MNode::Leaders(..) => (), MNode::Atom(MathAtom { nucleus, sub, sup }) => {
735 let sub = sub.map(|inner| {
736 |state: &mut Shipout<Math>| state.do_mathlist(&mut inner.into())
737 });
738 let sup = sup.map(|inner| {
739 |state: &mut Shipout<Math>| state.do_mathlist(&mut inner.into())
740 });
741 match nucleus {
742 MathNucleus::Accent { accent, inner } => {
743 self.accent(
744 accent.0,
745 accent.1,
746 |state| state.do_mathlist(&mut inner.into()),
747 sub,
748 sup,
749 )?;
750 }
751 MathNucleus::Inner(kernel) => {
752 self.inner(|state| state.do_kernel(kernel), sub, sup)?;
753 }
754 MathNucleus::Middle(char, s) => {
755 self.middle(char, s, sub, sup)?;
756 }
757 MathNucleus::Overline(kernel) => {
758 self.overline(|state| state.do_kernel(kernel), sub, sup)?;
759 }
760 MathNucleus::Underline(kernel) => {
761 self.underline(|state| state.do_kernel(kernel), sub, sup)?;
762 }
763 MathNucleus::LeftRight {
764 start,
765 end,
766 left,
767 right,
768 children,
769 } => {
770 self.left_right(
771 start,
772 end,
773 left,
774 right,
775 |state| state.do_mathlist(&mut children.into()),
776 sub,
777 sup,
778 )?;
779 }
780 MathNucleus::Radical { rad, inner } => {
781 self.radical(
782 rad.0,
783 rad.1,
784 |state| state.do_mathlist(&mut inner.into()),
785 sub,
786 sup,
787 )?;
788 }
789 MathNucleus::Simple {
790 cls,
791 kernel,
792 limits,
793 } => {
794 self.with_class(
795 cls,
796 limits.unwrap_or(false),
797 |state| state.do_kernel(kernel),
798 sub,
799 sup,
800 )?;
801 }
802 c @ MathNucleus::VCenter { .. } => {
803 let wd = c.width().0;
804 let MathNucleus::VCenter {
805 start,
806 end,
807 children,
808 ..
809 } = c
810 else {
811 unreachable!()
812 };
813 self.vcenter(
814 start,
815 end,
816 wd,
817 |state| state.do_vlist(&mut children.into()),
818 sub,
819 sup,
820 )?;
821 }
822 }
823 }
824 MathNode::Over {
825 start,
826 end,
827 top,
828 bottom,
829 sep,
830 left,
831 right,
832 } => {
833 self.over(
834 start,
835 end,
836 left,
837 right,
838 sep,
839 |state| state.do_mathlist(&mut top.into()).map_err(|_| ()),
840 |state| state.do_mathlist(&mut bottom.into()).map_err(|_| ()),
841 )?;
842 }
843 MathNode::VRule {
844 width,
845 height,
846 depth,
847 ..
848 } => self.push(ShipoutNodeM::VRule {
849 width,
850 height,
851 depth,
852 }),
853
854 _ => todo!("{c:?}"),
855 }
856 }
857 Ok(())
858 }
859 fn do_kernel(
860 &mut self,
861 kernel: MathKernel<Types, MathFontStyle<Types>>,
862 ) -> Result<(), Option<MathNode<Types, MathFontStyle<Types>>>> {
863 match kernel {
864 MathKernel::Char { char, style } => self.do_mathchar(
865 char,
866 style.font,
867 style.cramped,
868 style.style == MathStyleType::Display,
869 ),
870 MathKernel::List { children, .. } => self.do_mathlist(&mut children.into())?,
871 MathKernel::Empty => (),
872 MathKernel::Box(bx) => {
873 let _ = bx.width();
874 let _ = bx.height();
875 let _ = bx.depth();
876 let wd = bx.assigned_width();
877 let ht = bx.assigned_height();
878 let dp = bx.assigned_depth();
879 if bx.is_empty() {
880 match (wd, ht, dp) {
881 (Some(Dim32(0)) | None, Some(Dim32(0)) | None, Some(Dim32(0)) | None) => (),
882 _ => self.push(ShipoutNodeM::Phantom {
883 width: wd.map(|d| d.0).unwrap_or_default(),
884 height: ht.map(|d| d.0).unwrap_or_default(),
885 depth: dp.map(|d| d.0).unwrap_or_default(),
886 }),
887 }
888 } else {
889 match bx {
890 TeXBox::V {
891 start,
892 end,
893 info,
894 children,
895 ..
896 } => self
897 .in_v(start, end, info, |state| {
898 state.do_vlist(&mut children.into())
899 })
900 .map_err(|_| None)?,
901 TeXBox::H {
902 start,
903 end,
904 preskip,
905 info,
906 children,
907 ..
908 } => self
909 .in_h(start, end, info, preskip, |state| {
910 state.do_hlist(&mut children.into())
911 })
912 .map_err(|_| None)?,
913 }
914 }
915 }
916 }
917 Ok(())
918 }
919}
920
921impl Shipout<'_, '_, SVG> {
922 fn do_svglist(&mut self, children: &mut HNodes) -> Result<(), Option<HNode<Types>>> {
923 while let Some(c) = children.next() {
924 match c {
925 HNode::Custom(RusTeXNode::PDFNode(
926 PDFNode::PDFOutline(_)
927 | PDFNode::PDFPageAttr(_)
928 | PDFNode::PDFPagesAttr(_)
929 | PDFNode::PDFCatalog(_)
930 | PDFNode::PDFSave
931 | PDFNode::PDFAnnot(_)
932 | PDFNode::PDFLiteral(_)
933 | PDFNode::XForm(_)
934 | PDFNode::Obj(_),
935 ))
936 | HNode::Penalty(_)
937 | HNode::Mark(..)
938 | HNode::Custom(
939 RusTeXNode::PageBegin | RusTeXNode::PageEnd | RusTeXNode::HAlignEnd,
940 ) => (),
941 HNode::Custom(RusTeXNode::PDFNode(PDFNode::Color(act))) => self.do_color(act),
942 HNode::Custom(RusTeXNode::FontChange(font, global)) => self.open_font(font, global),
943 HNode::Custom(RusTeXNode::FontChangeEnd) => self.close_font(),
944 HNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFStartLink(link))) => {
945 self.open_link(link)
946 }
947 HNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFEndLink)) => self.close_link(),
948 HNode::Custom(RusTeXNode::AnnotBegin {
949 start,
950 attrs,
951 styles,
952 classes,
953 tag,
954 }) => self.open_annot(
955 start,
956 attrs.into(),
957 styles.into(),
958 classes.into_iter().map(String::into).collect(),
959 tag,
960 ),
961 HNode::Custom(RusTeXNode::AnnotEnd(end)) => self.close_annot(end),
962 HNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFMatrix {
963 scale,
964 rotate,
965 skewx,
966 skewy,
967 })) => self.open_matrix(scale, rotate, skewx, skewy),
968 HNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFRestore)) => self.close_matrix(),
969 HNode::Custom(RusTeXNode::PDFNode(PDFNode::PDFDest(PDFDest { id, .. }))) => {
970 self.push(Common::PDFDest(id).into())
971 }
972
973 HNode::Whatsit(wi) => wi.call(self.engine).map_err(|_| None)?,
974 HNode::Leaders(_) => (), HNode::Custom(RusTeXNode::Literal(s)) => self.push(Common::Literal(s).into()),
976
977 HNode::Custom(RusTeXNode::PGFGBegin { attrs, tag }) => self.open_node(attrs, tag),
978 HNode::Custom(RusTeXNode::PGFGEnd) => self.close_node(),
979 HNode::Box(TeXBox::H { children: chs, .. }) => children.prefix(chs.into_vec()),
980 HNode::Space | HNode::Hss => (),
981 HNode::Custom(RusTeXNode::PGFEscape(bx @ TeXBox::H { .. })) => {
982 let _ = bx.height();
983 let _ = bx.width();
984 let _ = bx.depth();
985 let TeXBox::H {
986 children,
987 start,
988 end,
989 info,
990 preskip,
991 ..
992 } = bx
993 else {
994 unreachable!()
995 };
996 self.in_h(start, end, info, preskip, |state| {
997 state.do_hlist(&mut children.into())
998 })
999 .map_err(|_| None)?
1000 }
1001 HNode::Custom(RusTeXNode::PGFEscape(bx @ TeXBox::V { .. })) => {
1002 let _ = bx.height();
1003 let _ = bx.width();
1004 let _ = bx.depth();
1005 let TeXBox::V {
1006 children,
1007 start,
1008 end,
1009 info,
1010 ..
1011 } = bx
1012 else {
1013 unreachable!()
1014 };
1015 self.in_v(start, end, info, |state| {
1016 state.do_vlist(&mut children.into())
1017 })
1018 .map_err(|_| None)?
1019 }
1020 HNode::MathGroup(ref mg) => {
1021 let bx = HBoxInfo::new_box(ToOrSpread::None);
1023 let MathGroup { start, end, .. } = mg;
1024 let start = start.clone();
1025 let end = end.clone();
1026 let children = vec![c];
1027 self.in_h(start, end, bx, None, |state| {
1028 state.do_hlist(&mut children.into())
1029 })
1030 .map_err(|_| None)?
1031 }
1032 HNode::Char { .. } => (), _ => todo!("{c:?}"),
1034 }
1035 }
1036 Ok(())
1037 }
1038}
1039
1040fn get_page_inner(children: Vec<VNode<Types>>) -> Vec<VNode<Types>> {
1041 let mut ret = Vec::new();
1042 let mut list: VNodes = children.into();
1043 while let Some(c) = list.next() {
1044 match c {
1045 VNode::Box(TeXBox::V { children, .. })
1046 if children
1047 .iter()
1048 .any(|n| matches!(n, VNode::Custom(RusTeXNode::PageBegin))) =>
1049 {
1050 ret.extend(children.into_vec().into_iter().filter(|p| {
1051 !matches!(
1052 p,
1053 VNode::Custom(RusTeXNode::PageBegin | RusTeXNode::PageEnd)
1054 )
1055 }))
1056 }
1057 VNode::Box(TeXBox::V { children, .. }) => list.prefix(children.into_vec()),
1058 VNode::Box(TeXBox::H { children, .. }) if hbox_works(&children) => {
1059 get_page_hbox(children, &mut ret, &mut list)
1060 }
1061 VNode::VSkip(_)
1062 | VNode::VKern(_)
1063 | VNode::VFil
1064 | VNode::VFill
1065 | VNode::VFilneg
1066 | VNode::Vss
1067 | VNode::Penalty(_)
1068 | VNode::Mark(..) => (),
1069 VNode::Custom(RusTeXNode::PDFNode(
1070 PDFNode::PDFDest(..)
1071 | PDFNode::PDFCatalog(_)
1072 | PDFNode::PDFLiteral(_)
1073 | PDFNode::XForm(..)
1074 | PDFNode::Obj(..)
1075 | PDFNode::PDFOutline(_),
1076 )) => (),
1077 VNode::Custom(RusTeXNode::PageBegin) => {
1078 for c in list.by_ref() {
1079 if let VNode::Custom(RusTeXNode::PageEnd) = c {
1080 break;
1081 } else {
1082 ret.push(c)
1083 }
1084 }
1085 }
1086 _ => ret.push(c),
1087 }
1088 }
1089 ret
1090}
1091
1092fn get_page_hbox(children: Box<[HNode<Types>]>, ret: &mut Vec<VNode<Types>>, list: &mut VNodes) {
1093 for c in children.into_vec().into_iter() {
1094 match c {
1095 HNode::HSkip(_)
1096 | HNode::Hss
1097 | HNode::Space
1098 | HNode::HKern(_)
1099 | HNode::HFil
1100 | HNode::HFill
1101 | HNode::HFilneg
1102 | HNode::Penalty(_)
1103 | HNode::Mark(_, _)
1104 | HNode::Custom(RusTeXNode::PDFNode(
1105 PDFNode::PDFDest(..)
1106 | PDFNode::PDFCatalog(_)
1107 | PDFNode::PDFLiteral(_)
1108 | PDFNode::XForm(..)
1109 | PDFNode::Obj(..)
1110 | PDFNode::PDFOutline(_),
1111 )) => (),
1112 HNode::Custom(
1113 n @ (RusTeXNode::PDFNode(PDFNode::Color(_))
1114 | RusTeXNode::FontChange(..)
1115 | RusTeXNode::FontChangeEnd),
1116 ) => ret.push(VNode::Custom(n)),
1117 HNode::Box(TeXBox::H { children, .. }) if hbox_works(&children) => {
1118 get_page_hbox(children, ret, list)
1119 }
1120 HNode::Box(b) => ret.push(VNode::Box(b)), _ => unreachable!(),
1122 }
1123 }
1124}
1125
1126fn hbox_works(children: &[HNode<Types>]) -> bool {
1127 children.iter().all(|n| {
1128 matches!(
1129 n,
1130 HNode::HSkip(_)
1131 | HNode::Hss
1132 | HNode::Space
1133 | HNode::HKern(_)
1134 | HNode::HFil
1135 | HNode::HFill
1136 | HNode::HFilneg
1137 | HNode::Penalty(_)
1138 | HNode::Mark(_, _)
1139 | HNode::Custom(RusTeXNode::PDFNode(
1140 PDFNode::PDFDest(..)
1141 | PDFNode::PDFCatalog(_)
1142 | PDFNode::PDFLiteral(_)
1143 | PDFNode::XForm(..)
1144 | PDFNode::Obj(..)
1145 | PDFNode::PDFOutline(_)
1146 ))
1147 | HNode::Box(TeXBox::H { .. })
1150 | HNode::Box(TeXBox::V { .. })
1151 )
1152 })
1153}