1use crate::Engine;
27use crate::primitives_gen::assign_int as ip;
28
29mod op {
31 pub const SET1: u8 = 128;
32 pub const SET_RULE: u8 = 132;
33 pub const BOP: u8 = 139;
34 pub const EOP: u8 = 140;
35 pub const PUSH: u8 = 141;
36 pub const POP: u8 = 142;
37 pub const RIGHT1: u8 = 143;
38 pub const DOWN1: u8 = 157;
39 pub const FNT_NUM_0: u8 = 171;
40 pub const FNT1: u8 = 235;
41 pub const XXX1: u8 = 239;
42 pub const XXX4: u8 = 242;
43 pub const FNT_DEF1: u8 = 243;
44 pub const PRE: u8 = 247;
45 pub const POST: u8 = 248;
46 pub const POST_POST: u8 = 249;
47}
48
49const ID_BYTE: u8 = 2;
51const NUM: i32 = 25_400_000;
53const DEN: i32 = 473_628_672;
54
55#[derive(Debug, Default)]
57pub struct DviWriter {
58 buf: Vec<u8>,
59 h: i32,
61 v: i32,
62 font: Option<u32>,
64 used: Vec<bool>,
66 last_bop: i32,
68 pages: u32,
70 max_v: i32,
72 max_h: i32,
74 max_push: i32,
76 stack: Vec<(usize, i32, i32)>,
79}
80
81impl DviWriter {
82 pub fn pages(&self) -> u32 {
84 self.pages
85 }
86
87 fn out(&mut self, b: u8) {
88 self.buf.push(b);
89 }
90
91 fn four(&mut self, x: i32) {
92 self.buf.extend_from_slice(&x.to_be_bytes());
93 }
94
95 fn bytes(&mut self, x: u32, n: usize) {
97 self.buf.extend_from_slice(&x.to_be_bytes()[4 - n..]);
98 }
99
100 fn unsigned_cmd(&mut self, base: u8, x: u32) {
103 let n = match x {
104 0..=0xff => 1,
105 0x100..=0xffff => 2,
106 0x1_0000..=0xff_ffff => 3,
107 _ => 4,
108 };
109 self.out(base + n as u8 - 1);
110 self.bytes(x, n);
111 }
112
113 fn movement(&mut self, w: i32, base: u8) {
116 let a = w.unsigned_abs();
117 let n = if a >= 0o40000000 {
118 4
119 } else if a >= 0o100000 {
120 3
121 } else if a >= 0o200 {
122 2
123 } else {
124 1
125 };
126 self.out(base + n as u8 - 1);
127 self.bytes(w as u32, n);
128 }
129
130 fn synch(&mut self, h: i32, v: i32) {
132 if h != self.h {
133 self.movement(h.wrapping_sub(self.h), op::RIGHT1);
134 self.h = h;
135 }
136 if v != self.v {
137 self.movement(v.wrapping_sub(self.v), op::DOWN1);
138 self.v = v;
139 }
140 }
141
142 pub fn begin_page(&mut self, engine: &mut Engine, dims: (i32, i32, i32), offsets: (i32, i32)) {
146 let (width, height, depth) = dims;
147 let (h_off, v_off) = offsets;
148 let t = height.wrapping_add(depth).wrapping_add(v_off);
149 if t > self.max_v {
150 self.max_v = t;
151 }
152 let t = width.wrapping_add(h_off);
153 if t > self.max_h {
154 self.max_h = t;
155 }
156 if self.pages == 0 {
157 engine.prepare_mag();
158 self.write_preamble(engine);
159 }
160 let page_loc = self.buf.len() as i32;
161 self.out(op::BOP);
162 for k in 0..10 {
163 self.four(engine.eqtb.count[k].val);
164 }
165 self.four(self.last_bop);
166 self.last_bop = page_loc;
167 self.h = 0;
168 self.v = 0;
169 self.font = None;
170 self.stack.clear();
171 }
172
173 fn write_preamble(&mut self, engine: &Engine) {
175 self.last_bop = -1;
176 self.out(op::PRE);
177 self.out(ID_BYTE);
178 self.four(NUM);
179 self.four(DEN);
180 self.four(engine.eqtb.int(ip::MAG));
181 let int = |i: u32| engine.eqtb.int(i);
182 let two = |n: i32| format!("{:02}", n.unsigned_abs() % 100);
183 let time = int(ip::TIME);
184 let comment = format!(
185 " LuaTeX output {}.{}.{}:{}{}",
186 int(ip::YEAR),
187 two(int(ip::MONTH)),
188 two(int(ip::DAY)),
189 two(time / 60),
190 two(time % 60)
191 );
192 let c = &comment.as_bytes()[..comment.len().min(255)];
193 self.out(c.len() as u8);
194 self.buf.extend_from_slice(c);
195 }
196
197 pub fn end_page(&mut self) {
199 self.out(op::EOP);
200 self.pages += 1;
201 }
202
203 pub fn push(&mut self, depth: i32) {
206 if depth > self.max_push {
207 self.max_push = depth;
208 }
209 self.out(op::PUSH);
210 self.stack.push((self.buf.len(), self.h, self.v));
211 }
212
213 pub fn note_depth(&mut self, depth: i32) {
215 if depth > self.max_push {
216 self.max_push = depth;
217 }
218 }
219
220 pub fn pop(&mut self) {
222 let Some((loc, h, v)) = self.stack.pop() else {
223 return;
224 };
225 if loc == self.buf.len() {
226 self.buf.pop();
227 } else {
228 self.out(op::POP);
229 }
230 self.h = h;
231 self.v = v;
232 }
233
234 pub fn glyph(&mut self, engine: &Engine, f: u32, chr: u32, h: i32, v: i32, width: i32) {
237 if f == 0 {
238 return;
239 }
240 self.synch(h, v);
241 if self.font != Some(f) {
242 let k = f - 1;
243 let idx = f as usize;
244 if self.used.len() <= idx {
245 self.used.resize(idx + 1, false);
246 }
247 if !self.used[idx] {
248 self.font_def(engine, f);
249 self.used[idx] = true;
250 }
251 if k < 64 {
252 self.out(op::FNT_NUM_0 + k as u8);
253 } else {
254 self.unsigned_cmd(op::FNT1, k);
255 }
256 self.font = Some(f);
257 }
258 if chr < 128 {
259 self.out(chr as u8);
260 } else {
261 self.unsigned_cmd(op::SET1, chr);
262 }
263 self.h = h.wrapping_add(width);
264 }
265
266 pub fn rule(&mut self, h: i32, v: i32, width: i32, height: i32) {
269 self.synch(h, v);
270 self.out(op::SET_RULE);
271 self.four(height);
272 self.four(width);
273 self.h = h.wrapping_add(width);
274 }
275
276 pub fn special(&mut self, h: i32, v: i32, data: &[u8]) {
278 self.synch(h, v);
279 if data.len() < 256 {
280 self.out(op::XXX1);
281 self.out(data.len() as u8);
282 } else {
283 self.out(op::XXX4);
284 self.four(data.len() as i32);
285 }
286 self.buf.extend_from_slice(data);
287 }
288
289 fn font_def(&mut self, engine: &Engine, f: u32) {
292 let fi = engine.font(f);
293 let checksum = fi.checksum;
294 let name = fi.name.rsplit(|&b| b == b'/').next().unwrap_or(&fi.name);
295 let name = &name[..name.len().min(255)];
296 let (size, dsize) = (fi.size, fi.design_size);
297 self.unsigned_cmd(op::FNT_DEF1, f - 1);
298 self.four(checksum as i32);
299 self.four(size);
300 self.four(dsize);
301 self.out(0);
302 self.out(name.len() as u8);
303 self.buf.extend_from_slice(name);
304 }
305
306 pub fn finish(&mut self, engine: &mut Engine) -> Vec<u8> {
308 self.out(op::POST);
309 self.four(self.last_bop);
310 self.last_bop = self.buf.len() as i32 - 5;
311 self.four(NUM);
312 self.four(DEN);
313 engine.prepare_mag();
314 self.four(engine.eqtb.int(ip::MAG));
315 self.four(self.max_v);
316 self.four(self.max_h);
317 self.bytes(self.max_push.clamp(0, 0xffff) as u32, 2);
318 self.bytes(self.pages & 0xffff, 2);
319 for f in (1..self.used.len()).rev() {
320 if self.used[f] {
321 self.font_def(engine, f as u32);
322 }
323 }
324 self.out(op::POST_POST);
325 self.four(self.last_bop);
326 self.out(ID_BYTE);
327 let k = 4 + (4 - self.buf.len() % 4) % 4;
328 for _ in 0..k {
329 self.out(223);
330 }
331 std::mem::take(&mut self.buf)
332 }
333}
334
335#[cfg(test)]
336mod tests {
337 use super::*;
338
339 #[test]
340 fn movement_lengths_follow_tex() {
341 let mut d = DviWriter::default();
342 for w in [127, -127, -128, 32767, -32768, 8388607, -8388608] {
343 d.movement(w, op::RIGHT1);
344 }
345 assert_eq!(
346 d.buf,
347 [
348 143, 127, 143, 129, 144, 255, 128, 144, 127, 255, 145, 255, 128, 0, 145, 127, 255,
349 255, 146, 255, 128, 0, 0
350 ]
351 );
352 }
353
354 #[test]
355 fn push_pop_without_output_cancels() {
356 let mut d = DviWriter::default();
357 d.push(1);
358 d.push(2);
359 d.pop();
360 d.pop();
361 assert!(d.buf.is_empty());
362 assert_eq!(d.max_push, 2);
363 d.push(1);
364 d.rule(5, 0, 1, 1);
365 d.pop();
366 assert_eq!(d.buf.first(), Some(&op::PUSH));
367 assert_eq!(d.buf.last(), Some(&op::POP));
368 assert_eq!((d.h, d.v), (0, 0));
369 }
370}