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 = engine.output_comment.clone().unwrap_or_else(|| {
185 format!(
186 " LuaTeX output {}.{}.{}:{}{}",
187 int(ip::YEAR),
188 two(int(ip::MONTH)),
189 two(int(ip::DAY)),
190 two(time / 60),
191 two(time % 60)
192 )
193 });
194 let c = &comment.as_bytes()[..comment.len().min(255)];
195 self.out(c.len() as u8);
196 self.buf.extend_from_slice(c);
197 }
198
199 pub fn end_page(&mut self) {
201 self.out(op::EOP);
202 self.pages += 1;
203 }
204
205 pub fn push(&mut self, depth: i32) {
208 if depth > self.max_push {
209 self.max_push = depth;
210 }
211 self.out(op::PUSH);
212 self.stack.push((self.buf.len(), self.h, self.v));
213 }
214
215 pub fn note_depth(&mut self, depth: i32) {
217 if depth > self.max_push {
218 self.max_push = depth;
219 }
220 }
221
222 pub fn pop(&mut self) {
224 let Some((loc, h, v)) = self.stack.pop() else {
225 return;
226 };
227 if loc == self.buf.len() {
228 self.buf.pop();
229 } else {
230 self.out(op::POP);
231 }
232 self.h = h;
233 self.v = v;
234 }
235
236 pub fn glyph(&mut self, engine: &Engine, f: u32, chr: u32, h: i32, v: i32, width: i32) {
239 if f == 0 {
240 return;
241 }
242 self.synch(h, v);
243 if self.font != Some(f) {
244 let k = f - 1;
245 let idx = f as usize;
246 if self.used.len() <= idx {
247 self.used.resize(idx + 1, false);
248 }
249 if !self.used[idx] {
250 self.font_def(engine, f);
251 self.used[idx] = true;
252 }
253 if k < 64 {
254 self.out(op::FNT_NUM_0 + k as u8);
255 } else {
256 self.unsigned_cmd(op::FNT1, k);
257 }
258 self.font = Some(f);
259 }
260 if chr < 128 {
261 self.out(chr as u8);
262 } else {
263 self.unsigned_cmd(op::SET1, chr);
264 }
265 self.h = h.wrapping_add(width);
266 }
267
268 pub fn rule(&mut self, h: i32, v: i32, width: i32, height: i32) {
271 self.synch(h, v);
272 self.out(op::SET_RULE);
273 self.four(height);
274 self.four(width);
275 self.h = h.wrapping_add(width);
276 }
277
278 pub fn special(&mut self, h: i32, v: i32, data: &[u8]) {
280 self.synch(h, v);
281 if data.len() < 256 {
282 self.out(op::XXX1);
283 self.out(data.len() as u8);
284 } else {
285 self.out(op::XXX4);
286 self.four(data.len() as i32);
287 }
288 self.buf.extend_from_slice(data);
289 }
290
291 fn font_def(&mut self, engine: &Engine, f: u32) {
294 let fi = engine.font(f);
295 let checksum = fi.checksum;
296 let name = fi.name.rsplit(|&b| b == b'/').next().unwrap_or(&fi.name);
297 let name = &name[..name.len().min(255)];
298 let (size, dsize) = (fi.size, fi.design_size);
299 self.unsigned_cmd(op::FNT_DEF1, f - 1);
300 self.four(checksum as i32);
301 self.four(size);
302 self.four(dsize);
303 self.out(0);
304 self.out(name.len() as u8);
305 self.buf.extend_from_slice(name);
306 }
307
308 pub fn finish(&mut self, engine: &mut Engine) -> Vec<u8> {
310 self.out(op::POST);
311 self.four(self.last_bop);
312 self.last_bop = self.buf.len() as i32 - 5;
313 self.four(NUM);
314 self.four(DEN);
315 engine.prepare_mag();
316 self.four(engine.eqtb.int(ip::MAG));
317 self.four(self.max_v);
318 self.four(self.max_h);
319 self.bytes(self.max_push.clamp(0, 0xffff) as u32, 2);
320 self.bytes(self.pages & 0xffff, 2);
321 for f in (1..self.used.len()).rev() {
322 if self.used[f] {
323 self.font_def(engine, f as u32);
324 }
325 }
326 self.out(op::POST_POST);
327 self.four(self.last_bop);
328 self.out(ID_BYTE);
329 let k = 4 + (4 - self.buf.len() % 4) % 4;
330 for _ in 0..k {
331 self.out(223);
332 }
333 std::mem::take(&mut self.buf)
334 }
335}
336
337#[cfg(test)]
338mod tests {
339 use super::*;
340
341 #[test]
342 fn movement_lengths_follow_tex() {
343 let mut d = DviWriter::default();
344 for w in [127, -127, -128, 32767, -32768, 8388607, -8388608] {
345 d.movement(w, op::RIGHT1);
346 }
347 assert_eq!(
348 d.buf,
349 [
350 143, 127, 143, 129, 144, 255, 128, 144, 127, 255, 145, 255, 128, 0, 145, 127, 255,
351 255, 146, 255, 128, 0, 0
352 ]
353 );
354 }
355
356 #[test]
357 fn push_pop_without_output_cancels() {
358 let mut d = DviWriter::default();
359 d.push(1);
360 d.push(2);
361 d.pop();
362 d.pop();
363 assert!(d.buf.is_empty());
364 assert_eq!(d.max_push, 2);
365 d.push(1);
366 d.rule(5, 0, 1, 1);
367 d.pop();
368 assert_eq!(d.buf.first(), Some(&op::PUSH));
369 assert_eq!(d.buf.last(), Some(&op::POP));
370 assert_eq!((d.h, d.v), (0, 0));
371 }
372}