use crate::Engine;
use crate::maincontrol::{IGNORE_DEPTH, Mode, ModeKind};
use crate::nodes::{NodeData, NodeRef, Whatsit, glyph_sub, id, kern_sub};
use crate::primitives_gen as pg;
pub const DIR_NAMES: [&str; 4] = ["TLT", "TRT", "LTL", "RTT"];
impl Engine {
pub fn print_font_id(&mut self, f: u32) {
let cs = self.font_id_cs(f);
let name = self.hash.name(cs).to_vec();
self.print_esc_bytes(&name);
}
pub fn print_font_and_char(&mut self, p: NodeRef) {
let (f, c) = match self.nodes.glyph(p) {
Some(g) => (g.font, g.chr),
None => return,
};
self.print_font_id(f);
self.printer.print_char(' ' as u32);
self.print_glyph_char(p, c);
}
fn print_glyph_char(&mut self, p: NodeRef, c: u32) {
match self.run_glyph_info(p) {
None => self.printer.print_char(c),
Some(Some(text)) => self.printer.print_callback_bytes(&text),
Some(None) => self.printer.print_hex(i64::from(c)),
}
}
pub fn short_display(&mut self, mut p: NodeRef) {
while !p.is_null() {
let n = self.nodes.get(p);
match &n.data {
NodeData::Glyph(g) => {
let (f, c, comps, sub) = (g.font, g.chr, g.components, n.subtype);
if sub & glyph_sub::LIGATURE != 0 && !comps.is_null() {
self.short_display(comps);
} else {
if i64::from(f) != self.ts.font_in_short_display {
self.print_font_id(f);
self.printer.print_char(' ' as u32);
self.ts.font_in_short_display = i64::from(f);
}
self.print_glyph_char(p, c);
}
}
NodeData::Box(_)
| NodeData::Ins { .. }
| NodeData::Whatsit(_)
| NodeData::Mark { .. }
| NodeData::Adjust { .. }
| NodeData::Unset { .. } => self.printer.print_str("[]"),
NodeData::Rule { .. } => self.printer.print_char('|' as u32),
NodeData::Glue { spec, .. } => {
if spec.width != 0 || spec.stretch != 0 || spec.shrink != 0 {
self.printer.print_char(' ' as u32);
}
}
NodeData::Math { .. } => self.printer.print_char('$' as u32),
NodeData::Disc { pre, post, .. } => {
let (pre, post) = (*pre, *post);
self.short_display(pre);
self.short_display(post);
}
_ => {}
}
p = self.nodes.next(p);
}
}
fn print_rule_dimen(&mut self, d: i32) {
if d == crate::typeset::NULL_FLAG {
self.printer.print_char('*' as u32);
} else {
self.printer.print_scaled(d);
}
}
fn node_list_display(&mut self, p: NodeRef, suffix: &[u8]) {
let n = self.ts.show_prefix.len();
self.ts.show_prefix.extend_from_slice(suffix);
self.show_node_list(p);
self.ts.show_prefix.truncate(n);
}
fn print_current_string(&mut self) {
let s = std::mem::take(&mut self.ts.show_prefix);
for &b in &s {
self.printer.print_char(u32::from(b));
}
self.ts.show_prefix = s;
}
pub fn show_node_list(&mut self, mut p: NodeRef) {
if self.ts.show_prefix.len() as i64 > i64::from(self.depth_threshold) {
if !p.is_null() {
self.printer.print_str(" []");
}
return;
}
let mut n = 0;
while !p.is_null() {
self.printer.print_ln();
self.print_current_string();
n += 1;
if n > self.breadth_max {
self.printer.print_str("etc.");
return;
}
self.display_node(p);
p = self.nodes.next(p);
}
}
pub fn display_node_list(&mut self, p: NodeRef) {
self.show_node_list(p);
}
fn display_node(&mut self, p: NodeRef) {
let node = self.nodes.get(p);
let (nid, sub) = (node.id, node.subtype);
match &node.data {
NodeData::Glyph(g) => {
let comps = g.components;
let f = g.font;
self.print_font_and_char(p);
if sub & glyph_sub::LIGATURE != 0 {
self.printer.print_str(" (ligature ");
if sub & glyph_sub::LEFT != 0 {
self.printer.print_char('|' as u32);
}
self.ts.font_in_short_display = i64::from(f);
self.short_display(comps);
if sub & glyph_sub::RIGHT != 0 {
self.printer.print_char('|' as u32);
}
self.printer.print_char(')' as u32);
}
}
NodeData::Box(b) => {
let b = (**b).clone();
self.print_esc_str(if nid == id::HLIST { "hbox(" } else { "vbox(" });
self.printer.print_scaled(b.height);
self.printer.print_char('+' as u32);
self.printer.print_scaled(b.depth);
self.printer.print_str(")x");
self.printer.print_scaled(b.width);
if b.glue_sign != 0 && b.glue_set != 0.0 {
self.printer.print_str(", glue set ");
if b.glue_sign == 2 {
self.printer.print_str("- ");
}
let g = b.glue_set;
if g.abs() > 20000.0 {
if g > 0.0 {
self.printer.print_char('>' as u32);
} else {
self.printer.print_str("< -");
}
self.print_glue(20000 * retex_arith::UNITY, b.glue_order, None);
} else {
self.print_glue(
(f64::from(retex_arith::UNITY) * g).round() as i32,
b.glue_order,
None,
);
}
}
if b.shift != 0 {
self.printer.print_str(", shifted ");
self.printer.print_scaled(b.shift);
}
self.printer.print_str(", direction ");
self.printer
.print_str(DIR_NAMES[(b.dir.rem_euclid(4)) as usize]);
self.node_list_display(b.head, b".");
}
NodeData::Unset {
b,
span_count,
stretch,
shrink,
stretch_order,
shrink_order,
} => {
let (h, d, w, head) = (b.height, b.depth, b.width, b.head);
let (sc, st, sh, sto, sho) = (
*span_count,
*stretch,
*shrink,
*stretch_order,
*shrink_order,
);
self.print_esc_str("unsetbox(");
self.printer.print_scaled(h);
self.printer.print_char('+' as u32);
self.printer.print_scaled(d);
self.printer.print_str(")x");
self.printer.print_scaled(w);
if sc != 0 {
self.printer.print_str(" (");
self.printer.print_int(i64::from(sc) + 1);
self.printer.print_str(" columns)");
}
if st != 0 {
self.printer.print_str(", stretch ");
self.print_glue(st, sto, None);
}
if sh != 0 {
self.printer.print_str(", shrink ");
self.print_glue(sh, sho, None);
}
self.node_list_display(head, b".");
}
NodeData::Rule {
width,
depth,
height,
..
} => {
let (w, d, h) = (*width, *depth, *height);
self.print_esc_str(match sub {
crate::image::IMAGE_RULE => "image(",
crate::image::BOX_RESOURCE_RULE => "box(",
_ => "rule(",
});
self.print_rule_dimen(h);
self.printer.print_char('+' as u32);
self.print_rule_dimen(d);
self.printer.print_str(")x");
self.print_rule_dimen(w);
}
NodeData::Ins {
cost,
depth,
height,
spec,
head,
} => {
let (cost, depth, height, spec, head) = (*cost, *depth, *height, *spec, *head);
self.print_esc_str("insert");
self.printer.print_int(i64::from(sub));
self.printer.print_str(", natural size ");
self.printer.print_scaled(height);
self.printer.print_str("; split(");
self.print_spec(&spec, None);
self.printer.print_char(',' as u32);
self.printer.print_scaled(depth);
self.printer.print_str("); float cost ");
self.printer.print_int(i64::from(cost));
self.node_list_display(head, b".");
}
NodeData::Whatsit(w) => {
let w = (**w).clone();
self.display_whatsit(&w, sub);
}
NodeData::Glue { spec, leader } => {
let (spec, leader) = (*spec, *leader);
if sub >= crate::nodes::glue_sub::A_LEADERS {
self.print_esc_str("");
match sub {
crate::nodes::glue_sub::C_LEADERS => self.printer.print_char('c' as u32),
crate::nodes::glue_sub::X_LEADERS => self.printer.print_char('x' as u32),
crate::nodes::glue_sub::G_LEADERS => self.printer.print_char('g' as u32),
_ => {}
}
self.printer.print_str("leaders ");
self.print_spec(&spec, None);
self.node_list_display(leader, b".");
} else {
self.print_esc_str("glue");
if sub != 0 {
self.printer.print_char('(' as u32);
if sub < crate::nodes::glue_sub::COND_MATH_GLUE {
self.print_skip_param(sub);
} else if sub == crate::nodes::glue_sub::COND_MATH_GLUE {
self.print_esc_str("nonscript");
} else {
self.print_esc_str("mskip");
}
self.printer.print_char(')' as u32);
}
if sub != crate::nodes::glue_sub::COND_MATH_GLUE {
self.printer.print_char(' ' as u32);
if sub < crate::nodes::glue_sub::COND_MATH_GLUE {
self.print_spec(&spec, None);
} else {
self.print_spec(&spec, Some("mu"));
}
}
}
}
NodeData::Kern { kern, .. } => {
let k = *kern;
if sub == crate::nodes::glue_sub::MU_GLUE {
self.print_esc_str("mkern");
self.printer.print_scaled(k);
self.printer.print_str("mu");
} else {
self.print_esc_str("kern");
self.printer.print_scaled(k);
match sub {
kern_sub::FONT => self.printer.print_str(" (font)"),
kern_sub::ACCENT => self.printer.print_str(" (accent)"),
kern_sub::ITALIC => self.printer.print_str(" (italic)"),
_ => {}
}
}
}
NodeData::MarginKern { width, .. } => {
let w = *width;
self.print_esc_str("kern");
self.printer.print_scaled(w);
if sub == 0 {
self.printer.print_str(" (left margin)");
} else {
self.printer.print_str(" (right margin)");
}
}
NodeData::Math { surround, glue } => {
let w = *surround;
let g = *glue;
self.print_esc_str("math");
self.printer.print_str(if sub == 0 { "on" } else { "off" });
if g.width != 0 || g.stretch != 0 || g.shrink != 0 {
self.printer.print_str(", glued ");
self.print_spec(&g, None);
} else if w != 0 {
self.printer.print_str(", surrounded ");
self.printer.print_scaled(w);
}
}
NodeData::Penalty { penalty } => {
let v = *penalty;
self.print_esc_str("penalty ");
self.printer.print_int(i64::from(v));
}
NodeData::Disc {
pre,
post,
replace,
penalty,
} => {
let (pre, post, replace, pen) = (*pre, *post, *replace, *penalty);
self.print_esc_str("discretionary");
self.printer.print_str(" (penalty ");
self.printer.print_int(i64::from(pen));
self.printer.print_char(')' as u32);
self.node_list_display(pre, b".< ");
self.node_list_display(post, b".> ");
self.node_list_display(replace, b".= ");
}
NodeData::Mark { class, mark } => {
let (class, mark) = (*class, mark.clone());
self.print_esc_str("mark");
if class != 0 {
self.printer.print_char('s' as u32);
self.printer.print_int(i64::from(class));
}
self.printer.print_char('{' as u32);
let lim = self.printer.max_print_line.saturating_sub(10) as i64;
self.show_token_list(&mark, 0, mark.len(), lim);
self.printer.print_char('}' as u32);
}
NodeData::Adjust { head } => {
let head = *head;
self.print_esc_str("vadjust");
if sub != 0 {
self.printer.print_str(" pre ");
}
self.node_list_display(head, b".");
}
NodeData::Boundary { value } => {
let v = *value;
match sub {
0 => self.print_esc_str("noboundary"),
1 => {
self.print_esc_str("boundary=");
self.printer.print_int(i64::from(v));
}
2 => {
self.print_esc_str("protrusionboundary=");
self.printer.print_int(i64::from(v));
}
_ => {
self.print_esc_str("wordboundary=");
self.printer.print_int(i64::from(v));
}
}
}
NodeData::LocalPar {
pen_inter,
pen_broken,
box_left,
box_right,
..
} => {
let (pi, pb, bl, br) = (*pen_inter, *pen_broken, *box_left, *box_right);
self.print_esc_str("localpar");
let base = self.ts.show_prefix.len();
self.ts.show_prefix.push(b'.');
self.printer.print_ln();
self.print_current_string();
self.print_esc_str("localinterlinepenalty=");
self.printer.print_int(i64::from(pi));
self.printer.print_ln();
self.print_current_string();
self.print_esc_str("localbrokenpenalty=");
self.printer.print_int(i64::from(pb));
for (name, b) in [("localleftbox", bl), ("localrightbox", br)] {
self.printer.print_ln();
self.print_current_string();
self.print_esc_str(name);
if b.is_null() {
self.printer.print_str("=null");
} else {
self.node_list_display(b, b".");
}
}
self.ts.show_prefix.truncate(base);
}
NodeData::Dir { dir, .. } => {
let d = *dir;
self.print_esc_str(if sub == 0 { "begindir " } else { "enddir " });
self.printer
.print_str(DIR_NAMES[(i32::from(d)).rem_euclid(4) as usize]);
}
NodeData::Temp | NodeData::Other(_) => {
self.printer.print_str("Unknown node type!");
}
_ => {
if !self.display_math_node(p) {
self.printer.print_str("Unknown node type!");
}
}
}
}
fn display_whatsit(&mut self, w: &Whatsit, sub: u16) {
match w {
Whatsit::Open { stream, name } => {
self.print_esc_str("openout");
self.print_write_stream(*stream as i32);
self.printer.print_char('=' as u32);
self.printer.print_bytes(name);
}
Whatsit::Write { stream, data } => {
self.print_esc_str("write");
self.print_write_stream(*stream);
self.printer.print_char('{' as u32);
let lim = self.printer.max_print_line.saturating_sub(10) as i64;
self.show_token_list(data, 0, data.len(), lim);
self.printer.print_char('}' as u32);
}
Whatsit::Close { stream } => {
self.print_esc_str("closeout");
self.print_write_stream(*stream as i32);
}
Whatsit::Special { data } => {
self.print_esc_str("special");
self.printer.print_char('{' as u32);
self.print_mark_bytes(data);
self.printer.print_char('}' as u32);
}
Whatsit::LateLua { data, .. } => {
self.print_esc_str("latelua0");
self.print_late_data(data);
}
Whatsit::PdfLiteral { data, mode, late } => {
self.print_esc_str(if *late {
"pdflateliteral "
} else {
"pdfliteral "
});
self.printer.print_str(match mode {
0 => "origin",
1 => "page",
2 => "direct",
3 => "raw",
4 => "text",
_ => "font",
});
self.print_late_data(data);
}
Whatsit::SavePos => self.print_esc_str("savepos"),
Whatsit::PdfColorstack { stack, cmd, data } => {
self.print_esc_str("pdfcolorstack ");
self.printer.print_int(i64::from(*stack));
self.printer.print_str(match cmd {
0 => " set ",
1 => " push ",
2 => " pop",
_ => " current",
});
if *cmd < 2 {
self.printer.print_char('{' as u32);
self.print_mark_bytes(data);
self.printer.print_char('}' as u32);
}
}
Whatsit::PdfSetmatrix { data } => {
self.print_esc_str("pdfsetmatrix");
self.printer.print_char('{' as u32);
self.print_mark_bytes(data);
self.printer.print_char('}' as u32);
}
Whatsit::PdfSave => self.print_esc_str("pdfsave"),
Whatsit::PdfRestore => self.print_esc_str("pdfrestore"),
Whatsit::Other { fields, data } => self.display_other_whatsit(sub, fields, data),
Whatsit::PdfLinkState { state } => {
self.print_esc_str("pdflinkstate ");
self.printer.print_int(i64::from(*state));
}
Whatsit::UserDefined { user_id, value } => {
self.print_esc_str("whatsit");
self.printer.print_int(i64::from(*user_id));
self.printer.print_char('=' as u32);
match value {
crate::nodes::UserValue::Int(n) | crate::nodes::UserValue::Lua(n) => {
self.printer.print_int(i64::from(*n))
}
crate::nodes::UserValue::Str(s) => {
self.printer.print_char('"' as u32);
self.printer.print_bytes(s);
self.printer.print_char('"' as u32);
}
crate::nodes::UserValue::Tokens(t) => {
self.printer.print_char('{' as u32);
let t = t.clone();
self.show_token_list(&t, 0, t.len(), i64::MAX);
self.printer.print_char('}' as u32);
}
crate::nodes::UserValue::Nodes(p) => {
self.printer.print_char('[' as u32);
let p = *p;
self.show_node_list(p);
self.printer.print_char(']' as u32);
}
crate::nodes::UserValue::Attr => self.printer.print_str("<>"),
}
}
Whatsit::PdfAnnot { dims, data, .. } => {
self.print_esc_str("pdfannot");
self.print_pdf_dims(*dims);
self.printer.print_char('{' as u32);
self.print_mark_bytes(data);
self.printer.print_char('}' as u32);
}
Whatsit::PdfStartLink {
dims, attr, action, ..
} => {
self.print_esc_str("pdfstartlink");
self.print_pdf_dims(*dims);
if !attr.is_empty() {
self.printer.print_str(" attr{");
self.print_mark_bytes(attr);
self.printer.print_char('}' as u32);
}
self.printer.print_str(" action ");
self.print_pdf_action(action);
}
Whatsit::PdfEndLink => self.print_esc_str("pdfendlink"),
Whatsit::PdfDest { id, view, .. } => {
use crate::pdfext::{DestId, DestKind};
self.print_esc_str("pdfdest ");
match id {
DestId::Num(n) => {
self.printer.print_str("num");
self.printer.print_int(i64::from(*n));
}
DestId::Name(n) => {
self.printer.print_str("name{");
self.print_mark_bytes(n);
self.printer.print_char('}' as u32);
}
}
self.printer.print_str(match view.kind {
DestKind::Xyz => " xyz",
DestKind::Fit => " fit",
DestKind::FitH => " fith",
DestKind::FitV => " fitv",
DestKind::FitB => " fitb",
DestKind::FitBH => " fitbh",
DestKind::FitBV => " fitbv",
DestKind::FitR => " fitr",
});
if view.kind == DestKind::Xyz && view.zoom != 0 {
self.printer.print_str(" zoom");
self.printer.print_int(i64::from(view.zoom));
}
if view.kind == DestKind::FitR {
self.print_pdf_dims(view.dims);
}
}
Whatsit::PdfRefobj { objnum } => self.show_refobj(i64::from(*objnum)),
}
}
fn show_refobj(&mut self, objnum: i64) {
self.print_esc_str("pdfrefobj");
let Some(obj) = i32::try_from(objnum)
.ok()
.and_then(|n| self.pdf.objects.get(&n))
.filter(|o| o.defined && !o.written)
.cloned()
else {
return;
};
if !obj.attr.is_empty() {
self.printer.print_str(" attr ");
self.printer.print_bytes(&obj.attr);
}
if obj.stream {
self.printer.print_str(" stream");
}
if obj.file {
self.printer.print_str(" file");
}
self.printer.print_char(' ' as u32);
self.printer.print_bytes(&obj.data);
}
fn print_pdf_dims(&mut self, d: [i32; 3]) {
self.printer.print_char('(' as u32);
self.print_rule_dimen(d[1]);
self.printer.print_char('+' as u32);
self.print_rule_dimen(d[2]);
self.printer.print_str(")x");
self.print_rule_dimen(d[0]);
}
fn print_pdf_action(&mut self, a: &crate::pdfext::PdfAction) {
use crate::pdfext::{ActionTarget, PdfAction};
let (file, target, goto) = match a {
PdfAction::User(u) => {
self.printer.print_str("user{");
self.print_mark_bytes(u);
self.printer.print_char('}' as u32);
return;
}
PdfAction::Goto {
file,
target,
structure,
..
} => {
match structure {
Some(ActionTarget::Name(n)) => {
self.printer.print_str("struct name{");
self.print_mark_bytes(n);
self.printer.print_str("} ");
}
Some(ActionTarget::Num(n)) => {
self.printer.print_str("struct num");
self.printer.print_int(i64::from(*n));
self.printer.print_char(' ' as u32);
}
_ => {}
}
(file, target, true)
}
PdfAction::Thread { file, target } => (file, target, false),
};
if let Some(f) = file {
self.printer.print_str("file{");
self.print_mark_bytes(f);
self.printer.print_str("} ");
}
match target {
ActionTarget::Page(p, spec) => {
self.printer.print_str("page");
self.printer.print_int(i64::from(*p));
self.printer.print_char('{' as u32);
self.print_mark_bytes(spec);
self.printer.print_char('}' as u32);
}
ActionTarget::Name(n) => {
self.printer
.print_str(if goto { "goto name{" } else { "thread name{" });
self.print_mark_bytes(n);
self.printer.print_char('}' as u32);
}
ActionTarget::Num(n) => {
self.printer
.print_str(if goto { "goto num" } else { "thread num" });
self.printer.print_int(i64::from(*n));
}
}
}
fn print_mark_bytes(&mut self, data: &[u8]) {
let limit = self.printer.max_print_line.saturating_sub(10);
let mut count = 0;
let mut cut = None;
for (i, &b) in data.iter().enumerate() {
if b & 0xC0 != 0x80 {
if count == limit {
cut = Some(i);
break;
}
count += 1;
}
}
match cut {
None => self.printer.print_bytes(data),
Some(i) => {
self.printer.print_bytes(&data[..i]);
self.print_esc_str("ETC.");
}
}
}
fn display_other_whatsit(&mut self, sub: u16, fields: &[i64], data: &[u8]) {
use crate::nodes::whatsit_sub as ws;
let split = |d: &[u8]| -> (Vec<u8>, Vec<u8>) {
match d.iter().position(|&b| b == 0) {
Some(i) => (d[..i].to_vec(), d[i + 1..].to_vec()),
None => (d.to_vec(), Vec::new()),
}
};
let dims = |e: &mut Engine, f: &[i64]| {
if f.len() >= 3 {
e.printer.print_char('(' as u32);
e.print_rule_dimen(f[1] as i32);
e.printer.print_char('+' as u32);
e.print_rule_dimen(f[2] as i32);
e.printer.print_str(")x");
e.print_rule_dimen(f[0] as i32);
}
};
match sub {
ws::PDF_END_LINK => self.print_esc_str("pdfendlink"),
ws::PDF_REFOBJ => self.show_refobj(fields.first().copied().unwrap_or(0)),
ws::PDF_DEST => {
let (name, kind) = split(data);
self.print_esc_str("pdfdest ");
if !name.is_empty() && name.iter().all(u8::is_ascii_digit) {
self.printer.print_str("num");
self.printer.print_bytes(&name);
} else {
self.printer.print_str("name{");
self.print_mark_bytes(&name);
self.printer.print_char('}' as u32);
}
self.printer.print_char(' ' as u32);
self.printer.print_bytes(&kind);
}
ws::PDF_START_LINK => {
let (attr, action) = split(data);
self.print_esc_str("pdfstartlink");
dims(self, fields);
if !attr.is_empty() {
self.printer.print_str(" attr{");
self.print_mark_bytes(&attr);
self.printer.print_char('}' as u32);
}
self.printer.print_str(" action ");
let a = String::from_utf8_lossy(&action).into_owned();
if let Some(rest) = a.strip_prefix("/S /GoTo ") {
self.printer.print_str("goto ");
if let Some(n) = rest.strip_prefix("/Num ") {
self.printer.print_str("num");
self.printer.print_str(n.trim());
} else if let Some(n) = rest.strip_prefix("/Name (") {
self.printer.print_str("name{");
self.printer.print_str(n.trim_end_matches(')'));
self.printer.print_char('}' as u32);
} else {
self.printer.print_str(rest);
}
} else {
self.printer.print_str("user{");
self.print_mark_bytes(&action);
self.printer.print_char('}' as u32);
}
}
ws::PDF_ANNOT => {
self.print_esc_str("pdfannot");
dims(self, fields);
self.printer.print_char('{' as u32);
self.print_mark_bytes(data);
self.printer.print_char('}' as u32);
}
_ => self.printer.print_str("whatsit?"),
}
}
fn print_late_data(&mut self, data: &crate::nodes::LateData) {
match data {
crate::nodes::LateData::Tokens(t) => {
self.printer.print_char('{' as u32);
let lim = self.printer.max_print_line.saturating_sub(10) as i64;
self.show_token_list(t, 0, t.len(), lim);
self.printer.print_char('}' as u32);
}
crate::nodes::LateData::Bytes(b) => {
self.printer.print_char('{' as u32);
self.print_mark_bytes(b);
self.printer.print_char('}' as u32);
}
crate::nodes::LateData::Lua { reference, .. } => {
self.printer.print_str(" <lua data reference ");
self.printer.print_int(i64::from(*reference));
self.printer.print_char('>' as u32);
}
}
}
fn print_write_stream(&mut self, s: i32) {
if (0..16).contains(&s) {
self.printer.print_int(i64::from(s));
} else if s == 16 {
self.printer.print_char('*' as u32);
} else {
self.printer.print_char('-' as u32);
}
}
pub fn print_skip_param(&mut self, sub: u16) {
use crate::nodes::glue_sub as g;
let name = match sub {
g::LINE_SKIP => "lineskip",
g::BASELINE_SKIP => "baselineskip",
g::PAR_SKIP => "parskip",
g::ABOVE_DISPLAY => "abovedisplayskip",
g::BELOW_DISPLAY => "belowdisplayskip",
g::ABOVE_DISPLAY_SHORT => "abovedisplayshortskip",
g::BELOW_DISPLAY_SHORT => "belowdisplayshortskip",
g::LEFT_SKIP => "leftskip",
g::RIGHT_SKIP => "rightskip",
g::TOP_SKIP => "topskip",
g::SPLIT_TOP_SKIP => "splittopskip",
g::TAB_SKIP => "tabskip",
g::SPACE_SKIP => "spaceskip",
g::XSPACE_SKIP => "xspaceskip",
g::PAR_FILL_SKIP => "parfillskip",
g::MATH_SKIP => "mathskip",
g::THIN_MU_SKIP => "thinmuskip",
g::MED_MU_SKIP => "medmuskip",
g::THICK_MU_SKIP => "thickmuskip",
_ => {
self.printer.print_str("[unknown glue parameter!]");
return;
}
};
self.print_esc_str(name);
}
pub fn show_activities(&mut self) {
self.printer.print_nl("");
self.printer.print_ln();
for i in (0..self.nest.len()).rev() {
let (mode, line, head, aux_pd, sf, pg, lang) = {
let l = &self.nest[i];
(
l.mode,
l.mode_line,
l.head,
l.prev_depth,
l.space_factor,
l.prev_graf,
l.clang,
)
};
self.printer.print_nl("### ");
self.print_mode(mode);
self.printer.print_str(" entered at line ");
self.printer.print_int(i64::from(line.abs()));
if line < 0 {
self.printer.print_str(" (\\output routine)");
}
if i == 0 {
self.show_page_contents();
if !self.nodes.next(self.page.contrib_head).is_null() {
self.printer.print_nl("### recent contributions:");
}
}
let first = self.nodes.next(head);
self.show_box(first);
match mode.abs_kind() {
ModeKind::Vertical => {
self.printer.print_nl("prevdepth ");
if aux_pd <= IGNORE_DEPTH {
self.printer.print_str("ignored");
} else {
self.printer.print_scaled(aux_pd);
}
if pg != 0 {
self.printer.print_str(", prevgraf ");
self.printer.print_int(i64::from(pg));
self.printer
.print_str(if pg != 1 { " lines" } else { " line" });
}
}
ModeKind::Horizontal => {
self.printer.print_nl("spacefactor ");
self.printer.print_int(i64::from(sf));
if mode == Mode::Horizontal && lang > 0 {
self.printer.print_str(", current language ");
self.printer.print_int(i64::from(lang));
}
}
ModeKind::Math => {
let inc = self.nest[i].incompleat_noad;
if !inc.is_null() {
self.printer.print_str("this will be denominator of:");
self.show_box(inc);
}
}
ModeKind::None => {}
}
}
}
pub fn show_page_contents(&mut self) {
let head = self.page.page_head;
if head == self.page.page_tail {
return;
}
self.printer.print_nl("### current page:");
if self.ts.output_active {
self.printer.print_str(" (held over for next output)");
}
let first = self.nodes.next(head);
self.show_box(first);
if self.page.contents != crate::typeset::PageContents::Empty {
self.printer.print_nl("total height ");
self.print_totals();
self.printer.print_nl(" goal height ");
self.printer.print_scaled(self.page.so_far[0]);
let ins: Vec<crate::typeset::PageIns> = self.page.ins.clone();
for r in ins {
self.printer.print_ln();
self.print_esc_str("insert");
self.printer.print_int(i64::from(r.n));
self.printer.print_str(" adds ");
let c = self.eqtb.count[r.n as usize].val;
let t = if c == 1000 {
r.height
} else {
retex_arith::x_over_n(r.height, 1000)
.map(|d| d.quotient)
.unwrap_or(0)
.wrapping_mul(c)
};
self.printer.print_scaled(t);
if r.split_up {
let mut q = head;
let mut t = 0;
loop {
q = self.nodes.next(q);
if q.is_null() {
break;
}
if self.nodes.id(q) == id::INS && u32::from(self.nodes.subtype(q)) == r.n {
t += 1;
}
if q == r.broken_ins {
break;
}
}
self.printer.print_str(", #");
self.printer.print_int(t);
self.printer.print_str(" might split");
}
}
}
}
pub fn print_totals(&mut self) {
let s = self.page.so_far;
self.printer.print_scaled(s[1]);
let names = ["", "fi", "fil", "fill", "filll"];
for (o, nm) in names.iter().enumerate() {
let v = self.page.stretch(o as u8);
if v != 0 {
self.printer.print_str(" plus ");
self.printer.print_scaled(v);
self.printer.print_str(nm);
}
}
if s[6] != 0 {
self.printer.print_str(" minus ");
self.printer.print_scaled(s[6]);
}
}
pub fn show_box_param_limits(&mut self) {
self.depth_threshold = self.eqtb.int(pg::assign_int::SHOWBOXDEPTH);
self.breadth_max = self.eqtb.int(pg::assign_int::SHOWBOXBREADTH);
if self.breadth_max <= 0 {
self.breadth_max = 5;
}
}
}