1use crate::Engine;
26use crate::maincontrol::{IGNORE_DEPTH, Mode, ModeKind};
27use crate::nodes::{NodeData, NodeRef, Whatsit, glyph_sub, id, kern_sub};
28use crate::primitives_gen as pg;
29
30pub const DIR_NAMES: [&str; 4] = ["TLT", "TRT", "LTL", "RTT"];
32
33impl Engine {
34 pub fn print_font_id(&mut self, f: u32) {
36 let cs = self.font_id_cs(f);
37 let name = self.hash.name(cs).to_vec();
38 self.print_esc_bytes(&name);
39 }
40
41 pub fn print_font_and_char(&mut self, p: NodeRef) {
43 let (f, c) = match self.nodes.glyph(p) {
44 Some(g) => (g.font, g.chr),
45 None => return,
46 };
47 self.print_font_id(f);
48 self.printer.print_char(' ' as u32);
49 self.print_glyph_char(p, c);
50 }
51
52 fn print_glyph_char(&mut self, p: NodeRef, c: u32) {
55 match self.run_glyph_info(p) {
56 None => self.printer.print_char(c),
57 Some(Some(text)) => self.printer.print_callback_bytes(&text),
58 Some(None) => self.printer.print_hex(i64::from(c)),
60 }
61 }
62
63 pub fn short_display(&mut self, mut p: NodeRef) {
65 while !p.is_null() {
66 let n = self.nodes.get(p);
67 match &n.data {
68 NodeData::Glyph(g) => {
69 let (f, c, comps, sub) = (g.font, g.chr, g.components, n.subtype);
70 if sub & glyph_sub::LIGATURE != 0 && !comps.is_null() {
71 self.short_display(comps);
72 } else {
73 if i64::from(f) != self.ts.font_in_short_display {
74 self.print_font_id(f);
75 self.printer.print_char(' ' as u32);
76 self.ts.font_in_short_display = i64::from(f);
77 }
78 self.print_glyph_char(p, c);
79 }
80 }
81 NodeData::Box(_)
82 | NodeData::Ins { .. }
83 | NodeData::Whatsit(_)
84 | NodeData::Mark { .. }
85 | NodeData::Adjust { .. }
86 | NodeData::Unset { .. } => self.printer.print_str("[]"),
87 NodeData::Rule { .. } => self.printer.print_char('|' as u32),
88 NodeData::Glue { spec, .. } => {
89 if spec.width != 0 || spec.stretch != 0 || spec.shrink != 0 {
90 self.printer.print_char(' ' as u32);
91 }
92 }
93 NodeData::Math { .. } => self.printer.print_char('$' as u32),
94 NodeData::Disc { pre, post, .. } => {
95 let (pre, post) = (*pre, *post);
96 self.short_display(pre);
97 self.short_display(post);
98 }
99 _ => {}
100 }
101 p = self.nodes.next(p);
102 }
103 }
104
105 fn print_rule_dimen(&mut self, d: i32) {
106 if d == crate::typeset::NULL_FLAG {
107 self.printer.print_char('*' as u32);
108 } else {
109 self.printer.print_scaled(d);
110 }
111 }
112
113 fn node_list_display(&mut self, p: NodeRef, suffix: &[u8]) {
116 let n = self.ts.show_prefix.len();
117 self.ts.show_prefix.extend_from_slice(suffix);
118 self.show_node_list(p);
119 self.ts.show_prefix.truncate(n);
120 }
121
122 fn print_current_string(&mut self) {
124 let s = std::mem::take(&mut self.ts.show_prefix);
125 for &b in &s {
126 self.printer.print_char(u32::from(b));
127 }
128 self.ts.show_prefix = s;
129 }
130
131 pub fn show_node_list(&mut self, mut p: NodeRef) {
133 if self.ts.show_prefix.len() as i64 > i64::from(self.depth_threshold) {
134 if !p.is_null() {
135 self.printer.print_str(" []");
136 }
137 return;
138 }
139 let mut n = 0;
140 while !p.is_null() {
141 self.printer.print_ln();
142 self.print_current_string();
143 n += 1;
144 if n > self.breadth_max {
145 self.printer.print_str("etc.");
146 return;
147 }
148 self.display_node(p);
149 p = self.nodes.next(p);
150 }
151 }
152
153 pub fn display_node_list(&mut self, p: NodeRef) {
155 self.show_node_list(p);
156 }
157
158 fn display_node(&mut self, p: NodeRef) {
160 let node = self.nodes.get(p);
161 let (nid, sub) = (node.id, node.subtype);
162 match &node.data {
163 NodeData::Glyph(g) => {
164 let comps = g.components;
165 let f = g.font;
166 self.print_font_and_char(p);
167 if sub & glyph_sub::LIGATURE != 0 {
168 self.printer.print_str(" (ligature ");
169 if sub & glyph_sub::LEFT != 0 {
170 self.printer.print_char('|' as u32);
171 }
172 self.ts.font_in_short_display = i64::from(f);
173 self.short_display(comps);
174 if sub & glyph_sub::RIGHT != 0 {
175 self.printer.print_char('|' as u32);
176 }
177 self.printer.print_char(')' as u32);
178 }
179 }
180 NodeData::Box(b) => {
181 let b = (**b).clone();
182 self.print_esc_str(if nid == id::HLIST { "hbox(" } else { "vbox(" });
183 self.printer.print_scaled(b.height);
184 self.printer.print_char('+' as u32);
185 self.printer.print_scaled(b.depth);
186 self.printer.print_str(")x");
187 self.printer.print_scaled(b.width);
188 if b.glue_sign != 0 && b.glue_set != 0.0 {
189 self.printer.print_str(", glue set ");
190 if b.glue_sign == 2 {
191 self.printer.print_str("- ");
192 }
193 let g = b.glue_set;
194 if g.abs() > 20000.0 {
195 if g > 0.0 {
196 self.printer.print_char('>' as u32);
197 } else {
198 self.printer.print_str("< -");
199 }
200 self.print_glue(20000 * retex_arith::UNITY, b.glue_order, None);
201 } else {
202 self.print_glue(
203 (f64::from(retex_arith::UNITY) * g).round() as i32,
204 b.glue_order,
205 None,
206 );
207 }
208 }
209 if b.shift != 0 {
210 self.printer.print_str(", shifted ");
211 self.printer.print_scaled(b.shift);
212 }
213 self.printer.print_str(", direction ");
214 self.printer
215 .print_str(DIR_NAMES[(b.dir.rem_euclid(4)) as usize]);
216 self.node_list_display(b.head, b".");
217 }
218 NodeData::Unset {
219 b,
220 span_count,
221 stretch,
222 shrink,
223 stretch_order,
224 shrink_order,
225 } => {
226 let (h, d, w, head) = (b.height, b.depth, b.width, b.head);
227 let (sc, st, sh, sto, sho) = (
228 *span_count,
229 *stretch,
230 *shrink,
231 *stretch_order,
232 *shrink_order,
233 );
234 self.print_esc_str("unsetbox(");
235 self.printer.print_scaled(h);
236 self.printer.print_char('+' as u32);
237 self.printer.print_scaled(d);
238 self.printer.print_str(")x");
239 self.printer.print_scaled(w);
240 if sc != 0 {
241 self.printer.print_str(" (");
242 self.printer.print_int(i64::from(sc) + 1);
243 self.printer.print_str(" columns)");
244 }
245 if st != 0 {
246 self.printer.print_str(", stretch ");
247 self.print_glue(st, sto, None);
248 }
249 if sh != 0 {
250 self.printer.print_str(", shrink ");
251 self.print_glue(sh, sho, None);
252 }
253 self.node_list_display(head, b".");
254 }
255 NodeData::Rule {
256 width,
257 depth,
258 height,
259 ..
260 } => {
261 let (w, d, h) = (*width, *depth, *height);
262 self.print_esc_str(match sub {
263 crate::image::IMAGE_RULE => "image(",
264 crate::image::BOX_RESOURCE_RULE => "box(",
265 _ => "rule(",
266 });
267 self.print_rule_dimen(h);
268 self.printer.print_char('+' as u32);
269 self.print_rule_dimen(d);
270 self.printer.print_str(")x");
271 self.print_rule_dimen(w);
272 }
273 NodeData::Ins {
274 cost,
275 depth,
276 height,
277 spec,
278 head,
279 } => {
280 let (cost, depth, height, spec, head) = (*cost, *depth, *height, *spec, *head);
281 self.print_esc_str("insert");
282 self.printer.print_int(i64::from(sub));
283 self.printer.print_str(", natural size ");
284 self.printer.print_scaled(height);
285 self.printer.print_str("; split(");
286 self.print_spec(&spec, None);
287 self.printer.print_char(',' as u32);
288 self.printer.print_scaled(depth);
289 self.printer.print_str("); float cost ");
290 self.printer.print_int(i64::from(cost));
291 self.node_list_display(head, b".");
292 }
293 NodeData::Whatsit(w) => {
294 let w = (**w).clone();
295 self.display_whatsit(&w, sub);
296 }
297 NodeData::Glue { spec, leader } => {
298 let (spec, leader) = (*spec, *leader);
299 if sub >= crate::nodes::glue_sub::A_LEADERS {
300 self.print_esc_str("");
301 match sub {
302 crate::nodes::glue_sub::C_LEADERS => self.printer.print_char('c' as u32),
303 crate::nodes::glue_sub::X_LEADERS => self.printer.print_char('x' as u32),
304 crate::nodes::glue_sub::G_LEADERS => self.printer.print_char('g' as u32),
305 _ => {}
306 }
307 self.printer.print_str("leaders ");
308 self.print_spec(&spec, None);
309 self.node_list_display(leader, b".");
310 } else {
311 self.print_esc_str("glue");
312 if sub != 0 {
313 self.printer.print_char('(' as u32);
314 if sub < crate::nodes::glue_sub::COND_MATH_GLUE {
315 self.print_skip_param(sub);
316 } else if sub == crate::nodes::glue_sub::COND_MATH_GLUE {
317 self.print_esc_str("nonscript");
318 } else {
319 self.print_esc_str("mskip");
320 }
321 self.printer.print_char(')' as u32);
322 }
323 if sub != crate::nodes::glue_sub::COND_MATH_GLUE {
324 self.printer.print_char(' ' as u32);
325 if sub < crate::nodes::glue_sub::COND_MATH_GLUE {
326 self.print_spec(&spec, None);
327 } else {
328 self.print_spec(&spec, Some("mu"));
329 }
330 }
331 }
332 }
333 NodeData::Kern { kern, .. } => {
334 let k = *kern;
335 if sub == crate::nodes::glue_sub::MU_GLUE {
336 self.print_esc_str("mkern");
337 self.printer.print_scaled(k);
338 self.printer.print_str("mu");
339 } else {
340 self.print_esc_str("kern");
341 self.printer.print_scaled(k);
342 match sub {
343 kern_sub::FONT => self.printer.print_str(" (font)"),
344 kern_sub::ACCENT => self.printer.print_str(" (accent)"),
345 kern_sub::ITALIC => self.printer.print_str(" (italic)"),
346 _ => {}
347 }
348 }
349 }
350 NodeData::MarginKern { width, .. } => {
351 let w = *width;
352 self.print_esc_str("kern");
353 self.printer.print_scaled(w);
354 if sub == 0 {
355 self.printer.print_str(" (left margin)");
356 } else {
357 self.printer.print_str(" (right margin)");
358 }
359 }
360 NodeData::Math { surround, glue } => {
361 let w = *surround;
362 let g = *glue;
363 self.print_esc_str("math");
364 self.printer.print_str(if sub == 0 { "on" } else { "off" });
365 if g.width != 0 || g.stretch != 0 || g.shrink != 0 {
366 self.printer.print_str(", glued ");
367 self.print_spec(&g, None);
368 } else if w != 0 {
369 self.printer.print_str(", surrounded ");
370 self.printer.print_scaled(w);
371 }
372 }
373 NodeData::Penalty { penalty } => {
374 let v = *penalty;
375 self.print_esc_str("penalty ");
376 self.printer.print_int(i64::from(v));
377 }
378 NodeData::Disc {
379 pre,
380 post,
381 replace,
382 penalty,
383 } => {
384 let (pre, post, replace, pen) = (*pre, *post, *replace, *penalty);
385 self.print_esc_str("discretionary");
386 self.printer.print_str(" (penalty ");
387 self.printer.print_int(i64::from(pen));
388 self.printer.print_char(')' as u32);
389 self.node_list_display(pre, b".< ");
390 self.node_list_display(post, b".> ");
391 self.node_list_display(replace, b".= ");
392 }
393 NodeData::Mark { class, mark } => {
394 let (class, mark) = (*class, mark.clone());
395 self.print_esc_str("mark");
396 if class != 0 {
397 self.printer.print_char('s' as u32);
398 self.printer.print_int(i64::from(class));
399 }
400 self.printer.print_char('{' as u32);
401 let lim = self.printer.max_print_line.saturating_sub(10) as i64;
402 self.show_token_list(&mark, 0, mark.len(), lim);
403 self.printer.print_char('}' as u32);
404 }
405 NodeData::Adjust { head } => {
406 let head = *head;
407 self.print_esc_str("vadjust");
408 if sub != 0 {
409 self.printer.print_str(" pre ");
410 }
411 self.node_list_display(head, b".");
412 }
413 NodeData::Boundary { value } => {
414 let v = *value;
415 match sub {
416 0 => self.print_esc_str("noboundary"),
417 1 => {
418 self.print_esc_str("boundary=");
419 self.printer.print_int(i64::from(v));
420 }
421 2 => {
422 self.print_esc_str("protrusionboundary=");
423 self.printer.print_int(i64::from(v));
424 }
425 _ => {
426 self.print_esc_str("wordboundary=");
427 self.printer.print_int(i64::from(v));
428 }
429 }
430 }
431 NodeData::LocalPar {
432 pen_inter,
433 pen_broken,
434 box_left,
435 box_right,
436 ..
437 } => {
438 let (pi, pb, bl, br) = (*pen_inter, *pen_broken, *box_left, *box_right);
439 self.print_esc_str("localpar");
440 let base = self.ts.show_prefix.len();
441 self.ts.show_prefix.push(b'.');
442 self.printer.print_ln();
443 self.print_current_string();
444 self.print_esc_str("localinterlinepenalty=");
445 self.printer.print_int(i64::from(pi));
446 self.printer.print_ln();
447 self.print_current_string();
448 self.print_esc_str("localbrokenpenalty=");
449 self.printer.print_int(i64::from(pb));
450 for (name, b) in [("localleftbox", bl), ("localrightbox", br)] {
451 self.printer.print_ln();
452 self.print_current_string();
453 self.print_esc_str(name);
454 if b.is_null() {
455 self.printer.print_str("=null");
456 } else {
457 self.node_list_display(b, b".");
458 }
459 }
460 self.ts.show_prefix.truncate(base);
461 }
462 NodeData::Dir { dir, .. } => {
463 let d = *dir;
464 self.print_esc_str(if sub == 0 { "begindir " } else { "enddir " });
465 self.printer
466 .print_str(DIR_NAMES[(i32::from(d)).rem_euclid(4) as usize]);
467 }
468 NodeData::Temp | NodeData::Other(_) => {
469 self.printer.print_str("Unknown node type!");
470 }
471 _ => {
472 if !self.display_math_node(p) {
473 self.printer.print_str("Unknown node type!");
474 }
475 }
476 }
477 }
478
479 fn display_whatsit(&mut self, w: &Whatsit, sub: u16) {
481 match w {
482 Whatsit::Open { stream, name } => {
483 self.print_esc_str("openout");
484 self.print_write_stream(*stream as i32);
485 self.printer.print_char('=' as u32);
486 self.printer.print_bytes(name);
487 }
488 Whatsit::Write { stream, data } => {
489 self.print_esc_str("write");
490 self.print_write_stream(*stream);
491 self.printer.print_char('{' as u32);
492 let lim = self.printer.max_print_line.saturating_sub(10) as i64;
493 self.show_token_list(data, 0, data.len(), lim);
494 self.printer.print_char('}' as u32);
495 }
496 Whatsit::Close { stream } => {
497 self.print_esc_str("closeout");
498 self.print_write_stream(*stream as i32);
499 }
500 Whatsit::Special { data } => {
501 self.print_esc_str("special");
502 self.printer.print_char('{' as u32);
503 self.printer.print_bytes(data);
504 self.printer.print_char('}' as u32);
505 }
506 Whatsit::LateLua { data, .. } => {
507 self.print_esc_str("latelua0");
508 self.print_late_data(data);
509 }
510 Whatsit::PdfLiteral { data, mode, late } => {
511 self.print_esc_str(if *late {
512 "pdflateliteral "
513 } else {
514 "pdfliteral "
515 });
516 self.printer.print_str(match mode {
517 0 => "origin",
518 1 => "page",
519 2 => "direct",
520 3 => "raw",
521 4 => "text",
522 _ => "font",
523 });
524 self.print_late_data(data);
525 }
526 Whatsit::SavePos => self.print_esc_str("savepos"),
527 Whatsit::PdfColorstack { stack, cmd, data } => {
528 self.print_esc_str("pdfcolorstack ");
529 self.printer.print_int(i64::from(*stack));
530 self.printer.print_str(match cmd {
531 0 => " set ",
532 1 => " push ",
533 2 => " pop",
534 _ => " current",
535 });
536 if *cmd < 2 {
537 self.printer.print_char('{' as u32);
538 self.printer.print_bytes(data);
539 self.printer.print_char('}' as u32);
540 }
541 }
542 Whatsit::PdfSetmatrix { data } => {
543 self.print_esc_str("pdfsetmatrix");
544 self.printer.print_char('{' as u32);
545 self.printer.print_bytes(data);
546 self.printer.print_char('}' as u32);
547 }
548 Whatsit::PdfSave => self.print_esc_str("pdfsave"),
549 Whatsit::PdfRestore => self.print_esc_str("pdfrestore"),
550 Whatsit::Other { fields, data } => self.display_other_whatsit(sub, fields, data),
551 Whatsit::PdfLinkState { state } => {
552 self.print_esc_str("pdflinkstate ");
553 self.printer.print_int(i64::from(*state));
554 }
555 Whatsit::UserDefined { user_id, value } => {
556 self.print_esc_str("whatsit");
560 self.printer.print_int(i64::from(*user_id));
561 self.printer.print_char('=' as u32);
562 match value {
563 crate::nodes::UserValue::Int(n) | crate::nodes::UserValue::Lua(n) => {
564 self.printer.print_int(i64::from(*n))
565 }
566 crate::nodes::UserValue::Str(s) => {
567 self.printer.print_char('"' as u32);
568 self.printer.print_bytes(s);
569 self.printer.print_char('"' as u32);
570 }
571 crate::nodes::UserValue::Tokens(t) => {
572 self.printer.print_char('{' as u32);
573 let t = t.clone();
574 self.show_token_list(&t, 0, t.len(), i64::MAX);
575 self.printer.print_char('}' as u32);
576 }
577 crate::nodes::UserValue::Nodes(p) => {
578 self.printer.print_char('[' as u32);
579 let p = *p;
580 self.show_node_list(p);
581 self.printer.print_char(']' as u32);
582 }
583 crate::nodes::UserValue::Attr => self.printer.print_str("<>"),
584 }
585 }
586 Whatsit::PdfAnnot { dims, data, .. } => {
587 self.print_esc_str("pdfannot");
588 self.print_pdf_dims(*dims);
589 self.printer.print_char('{' as u32);
590 self.printer.print_bytes(data);
591 self.printer.print_char('}' as u32);
592 }
593 Whatsit::PdfStartLink {
594 dims, attr, action, ..
595 } => {
596 self.print_esc_str("pdfstartlink");
597 self.print_pdf_dims(*dims);
598 if !attr.is_empty() {
599 self.printer.print_str(" attr{");
600 self.printer.print_bytes(attr);
601 self.printer.print_char('}' as u32);
602 }
603 self.printer.print_str(" action ");
604 self.print_pdf_action(action);
605 }
606 Whatsit::PdfEndLink => self.print_esc_str("pdfendlink"),
607 Whatsit::PdfDest { id, view, .. } => {
609 use crate::pdfext::{DestId, DestKind};
610 self.print_esc_str("pdfdest ");
611 match id {
612 DestId::Num(n) => {
613 self.printer.print_str("num");
614 self.printer.print_int(i64::from(*n));
615 }
616 DestId::Name(n) => {
617 self.printer.print_str("name{");
618 self.printer.print_bytes(n);
619 self.printer.print_char('}' as u32);
620 }
621 }
622 self.printer.print_str(match view.kind {
623 DestKind::Xyz => " xyz",
624 DestKind::Fit => " fit",
625 DestKind::FitH => " fith",
626 DestKind::FitV => " fitv",
627 DestKind::FitB => " fitb",
628 DestKind::FitBH => " fitbh",
629 DestKind::FitBV => " fitbv",
630 DestKind::FitR => " fitr",
631 });
632 if view.kind == DestKind::Xyz && view.zoom != 0 {
633 self.printer.print_str(" zoom");
634 self.printer.print_int(i64::from(view.zoom));
635 }
636 if view.kind == DestKind::FitR {
637 self.print_pdf_dims(view.dims);
638 }
639 }
640 Whatsit::PdfRefobj { objnum } => self.show_refobj(i64::from(*objnum)),
641 }
642 }
643
644 fn show_refobj(&mut self, objnum: i64) {
649 self.print_esc_str("pdfrefobj");
650 let Some(obj) = i32::try_from(objnum)
651 .ok()
652 .and_then(|n| self.pdf.objects.get(&n))
653 .filter(|o| o.defined && !o.written)
654 .cloned()
655 else {
656 return;
657 };
658 if !obj.attr.is_empty() {
659 self.printer.print_str(" attr ");
660 self.printer.print_bytes(&obj.attr);
661 }
662 if obj.stream {
663 self.printer.print_str(" stream");
664 }
665 if obj.file {
666 self.printer.print_str(" file");
667 }
668 self.printer.print_char(' ' as u32);
669 self.printer.print_bytes(&obj.data);
670 }
671
672 fn print_pdf_dims(&mut self, d: [i32; 3]) {
675 self.printer.print_char('(' as u32);
676 self.print_rule_dimen(d[1]);
677 self.printer.print_char('+' as u32);
678 self.print_rule_dimen(d[2]);
679 self.printer.print_str(")x");
680 self.print_rule_dimen(d[0]);
681 }
682
683 fn print_pdf_action(&mut self, a: &crate::pdfext::PdfAction) {
686 use crate::pdfext::{ActionTarget, PdfAction};
687 let (file, target, goto) = match a {
688 PdfAction::User(u) => {
689 self.printer.print_str("user{");
690 self.printer.print_bytes(u);
691 self.printer.print_char('}' as u32);
692 return;
693 }
694 PdfAction::Goto {
695 file,
696 target,
697 structure,
698 ..
699 } => {
700 match structure {
702 Some(ActionTarget::Name(n)) => {
703 self.printer.print_str("struct name{");
704 self.printer.print_bytes(n);
705 self.printer.print_str("} ");
706 }
707 Some(ActionTarget::Num(n)) => {
708 self.printer.print_str("struct num");
709 self.printer.print_int(i64::from(*n));
710 self.printer.print_char(' ' as u32);
711 }
712 _ => {}
713 }
714 (file, target, true)
715 }
716 PdfAction::Thread { file, target } => (file, target, false),
717 };
718 if let Some(f) = file {
719 self.printer.print_str("file{");
720 self.printer.print_bytes(f);
721 self.printer.print_str("} ");
722 }
723 match target {
724 ActionTarget::Page(p, spec) => {
725 self.printer.print_str("page");
726 self.printer.print_int(i64::from(*p));
727 self.printer.print_char('{' as u32);
728 self.printer.print_bytes(spec);
729 self.printer.print_char('}' as u32);
730 }
731 ActionTarget::Name(n) => {
732 self.printer
733 .print_str(if goto { "goto name{" } else { "thread name{" });
734 self.printer.print_bytes(n);
735 self.printer.print_char('}' as u32);
736 }
737 ActionTarget::Num(n) => {
738 self.printer
739 .print_str(if goto { "goto num" } else { "thread num" });
740 self.printer.print_int(i64::from(*n));
741 }
742 }
743 }
744
745 fn display_other_whatsit(&mut self, sub: u16, fields: &[i64], data: &[u8]) {
748 use crate::nodes::whatsit_sub as ws;
749 let split = |d: &[u8]| -> (Vec<u8>, Vec<u8>) {
750 match d.iter().position(|&b| b == 0) {
751 Some(i) => (d[..i].to_vec(), d[i + 1..].to_vec()),
752 None => (d.to_vec(), Vec::new()),
753 }
754 };
755 let dims = |e: &mut Engine, f: &[i64]| {
756 if f.len() >= 3 {
757 e.printer.print_char('(' as u32);
758 e.print_rule_dimen(f[1] as i32);
759 e.printer.print_char('+' as u32);
760 e.print_rule_dimen(f[2] as i32);
761 e.printer.print_str(")x");
762 e.print_rule_dimen(f[0] as i32);
763 }
764 };
765 match sub {
766 ws::PDF_END_LINK => self.print_esc_str("pdfendlink"),
767 ws::PDF_REFOBJ => self.show_refobj(fields.first().copied().unwrap_or(0)),
768 ws::PDF_DEST => {
769 let (name, kind) = split(data);
770 self.print_esc_str("pdfdest ");
771 if !name.is_empty() && name.iter().all(u8::is_ascii_digit) {
772 self.printer.print_str("num");
773 self.printer.print_bytes(&name);
774 } else {
775 self.printer.print_str("name{");
776 self.printer.print_bytes(&name);
777 self.printer.print_char('}' as u32);
778 }
779 self.printer.print_char(' ' as u32);
780 self.printer.print_bytes(&kind);
781 }
782 ws::PDF_START_LINK => {
783 let (attr, action) = split(data);
784 self.print_esc_str("pdfstartlink");
785 dims(self, fields);
786 if !attr.is_empty() {
787 self.printer.print_str(" attr{");
788 self.printer.print_bytes(&attr);
789 self.printer.print_char('}' as u32);
790 }
791 self.printer.print_str(" action ");
792 let a = String::from_utf8_lossy(&action).into_owned();
793 if let Some(rest) = a.strip_prefix("/S /GoTo ") {
794 self.printer.print_str("goto ");
795 if let Some(n) = rest.strip_prefix("/Num ") {
796 self.printer.print_str("num");
797 self.printer.print_str(n.trim());
798 } else if let Some(n) = rest.strip_prefix("/Name (") {
799 self.printer.print_str("name{");
800 self.printer.print_str(n.trim_end_matches(')'));
801 self.printer.print_char('}' as u32);
802 } else {
803 self.printer.print_str(rest);
804 }
805 } else {
806 self.printer.print_str("user{");
807 self.printer.print_bytes(&action);
808 self.printer.print_char('}' as u32);
809 }
810 }
811 ws::PDF_ANNOT => {
812 self.print_esc_str("pdfannot");
813 dims(self, fields);
814 self.printer.print_char('{' as u32);
815 self.printer.print_bytes(data);
816 self.printer.print_char('}' as u32);
817 }
818 _ => self.printer.print_str("whatsit?"),
819 }
820 }
821
822 fn print_late_data(&mut self, data: &crate::nodes::LateData) {
823 match data {
824 crate::nodes::LateData::Tokens(t) => {
825 self.printer.print_char('{' as u32);
826 let lim = self.printer.max_print_line.saturating_sub(10) as i64;
827 self.show_token_list(t, 0, t.len(), lim);
828 self.printer.print_char('}' as u32);
829 }
830 crate::nodes::LateData::Bytes(b) => {
831 self.printer.print_char('{' as u32);
832 self.printer.print_bytes(b);
833 self.printer.print_char('}' as u32);
834 }
835 crate::nodes::LateData::Lua { reference, .. } => {
836 self.printer.print_str(" <lua data reference ");
837 self.printer.print_int(i64::from(*reference));
838 self.printer.print_char('>' as u32);
839 }
840 }
841 }
842
843 fn print_write_stream(&mut self, s: i32) {
844 if (0..16).contains(&s) {
845 self.printer.print_int(i64::from(s));
846 } else if s == 16 {
847 self.printer.print_char('*' as u32);
848 } else {
849 self.printer.print_char('-' as u32);
850 }
851 }
852
853 pub fn print_skip_param(&mut self, sub: u16) {
856 use crate::nodes::glue_sub as g;
857 let name = match sub {
858 g::LINE_SKIP => "lineskip",
859 g::BASELINE_SKIP => "baselineskip",
860 g::PAR_SKIP => "parskip",
861 g::ABOVE_DISPLAY => "abovedisplayskip",
862 g::BELOW_DISPLAY => "belowdisplayskip",
863 g::ABOVE_DISPLAY_SHORT => "abovedisplayshortskip",
864 g::BELOW_DISPLAY_SHORT => "belowdisplayshortskip",
865 g::LEFT_SKIP => "leftskip",
866 g::RIGHT_SKIP => "rightskip",
867 g::TOP_SKIP => "topskip",
868 g::SPLIT_TOP_SKIP => "splittopskip",
869 g::TAB_SKIP => "tabskip",
870 g::SPACE_SKIP => "spaceskip",
871 g::XSPACE_SKIP => "xspaceskip",
872 g::PAR_FILL_SKIP => "parfillskip",
873 g::MATH_SKIP => "mathskip",
874 g::THIN_MU_SKIP => "thinmuskip",
875 g::MED_MU_SKIP => "medmuskip",
876 g::THICK_MU_SKIP => "thickmuskip",
877 _ => {
878 self.printer.print_str("[unknown glue parameter!]");
879 return;
880 }
881 };
882 self.print_esc_str(name);
883 }
884
885 pub fn show_activities(&mut self) {
887 self.printer.print_nl("");
888 self.printer.print_ln();
889 for i in (0..self.nest.len()).rev() {
890 let (mode, line, head, aux_pd, sf, pg, lang) = {
891 let l = &self.nest[i];
892 (
893 l.mode,
894 l.mode_line,
895 l.head,
896 l.prev_depth,
897 l.space_factor,
898 l.prev_graf,
899 l.clang,
900 )
901 };
902 self.printer.print_nl("### ");
903 self.print_mode(mode);
904 self.printer.print_str(" entered at line ");
905 self.printer.print_int(i64::from(line.abs()));
906 if line < 0 {
907 self.printer.print_str(" (\\output routine)");
908 }
909 if i == 0 {
910 self.show_page_contents();
911 if !self.nodes.next(self.page.contrib_head).is_null() {
912 self.printer.print_nl("### recent contributions:");
913 }
914 }
915 let first = self.nodes.next(head);
916 self.show_box(first);
917 match mode.abs_kind() {
918 ModeKind::Vertical => {
919 self.printer.print_nl("prevdepth ");
920 if aux_pd <= IGNORE_DEPTH {
921 self.printer.print_str("ignored");
922 } else {
923 self.printer.print_scaled(aux_pd);
924 }
925 if pg != 0 {
926 self.printer.print_str(", prevgraf ");
927 self.printer.print_int(i64::from(pg));
928 self.printer
929 .print_str(if pg != 1 { " lines" } else { " line" });
930 }
931 }
932 ModeKind::Horizontal => {
933 self.printer.print_nl("spacefactor ");
934 self.printer.print_int(i64::from(sf));
935 if mode == Mode::Horizontal && lang > 0 {
936 self.printer.print_str(", current language ");
937 self.printer.print_int(i64::from(lang));
938 }
939 }
940 ModeKind::Math => {
941 let inc = self.nest[i].incompleat_noad;
942 if !inc.is_null() {
943 self.printer.print_str("this will be denominator of:");
944 self.show_box(inc);
945 }
946 }
947 ModeKind::None => {}
948 }
949 }
950 }
951
952 pub fn show_page_contents(&mut self) {
954 let head = self.page.page_head;
955 if head == self.page.page_tail {
956 return;
957 }
958 self.printer.print_nl("### current page:");
959 if self.ts.output_active {
960 self.printer.print_str(" (held over for next output)");
961 }
962 let first = self.nodes.next(head);
963 self.show_box(first);
964 if self.page.contents != crate::typeset::PageContents::Empty {
965 self.printer.print_nl("total height ");
966 self.print_totals();
967 self.printer.print_nl(" goal height ");
968 self.printer.print_scaled(self.page.so_far[0]);
969 let ins: Vec<crate::typeset::PageIns> = self.page.ins.clone();
970 for r in ins {
971 self.printer.print_ln();
972 self.print_esc_str("insert");
973 self.printer.print_int(i64::from(r.n));
974 self.printer.print_str(" adds ");
975 let c = self.eqtb.count[r.n as usize].val;
976 let t = if c == 1000 {
977 r.height
978 } else {
979 retex_arith::x_over_n(r.height, 1000)
980 .map(|d| d.quotient)
981 .unwrap_or(0)
982 .wrapping_mul(c)
983 };
984 self.printer.print_scaled(t);
985 if r.split_up {
986 let mut q = head;
987 let mut t = 0;
988 loop {
989 q = self.nodes.next(q);
990 if q.is_null() {
991 break;
992 }
993 if self.nodes.id(q) == id::INS && u32::from(self.nodes.subtype(q)) == r.n {
994 t += 1;
995 }
996 if q == r.broken_ins {
997 break;
998 }
999 }
1000 self.printer.print_str(", #");
1001 self.printer.print_int(t);
1002 self.printer.print_str(" might split");
1003 }
1004 }
1005 }
1006 }
1007
1008 pub fn print_totals(&mut self) {
1010 let s = self.page.so_far;
1011 self.printer.print_scaled(s[1]);
1012 let names = ["", "fi", "fil", "fill", "filll"];
1013 for (o, nm) in names.iter().enumerate() {
1016 let v = self.page.stretch(o as u8);
1017 if v != 0 {
1018 self.printer.print_str(" plus ");
1019 self.printer.print_scaled(v);
1020 self.printer.print_str(nm);
1021 }
1022 }
1023 if s[6] != 0 {
1024 self.printer.print_str(" minus ");
1025 self.printer.print_scaled(s[6]);
1026 }
1027 }
1028
1029 pub fn show_box_param_limits(&mut self) {
1032 self.depth_threshold = self.eqtb.int(pg::assign_int::SHOWBOXDEPTH);
1033 self.breadth_max = self.eqtb.int(pg::assign_int::SHOWBOXBREADTH);
1034 if self.breadth_max <= 0 {
1035 self.breadth_max = 5;
1036 }
1037 }
1038}