1#![allow(clippy::needless_range_loop)]
19
20use crate::Engine;
21use crate::build::PackSpec;
22use crate::glue::Glue;
23use crate::nodes::{NodeData, NodeRef, glue_sub, id, kern_sub};
24use crate::primitives_gen::{
25 assign_dimen as dp, assign_glue as gp, assign_int as ip, set_etex_shape as es,
26};
27use crate::typeset::{AWFUL_BAD, EJECT_PENALTY, INF_BAD, INF_PENALTY};
28
29const VERY_LOOSE_FIT: usize = 0;
30const LOOSE_FIT: usize = 1;
31const DECENT_FIT: usize = 2;
32const TIGHT_FIT: usize = 3;
33
34type Widths = [i32; NW];
37
38const NW: usize = 9;
40const FONT_STRETCH: usize = 7;
42const FONT_SHRINK: usize = 8;
44
45#[inline]
46fn add_glue(w: &mut Widths, g: &Glue) {
47 w[0] += g.width;
48 w[1 + (g.stretch_order as usize).min(4)] += g.stretch;
49 w[6] += g.shrink;
50}
51
52#[derive(Clone, Debug)]
54enum Entry {
55 Sentinel,
57 Active {
59 passive: Option<usize>,
60 line_number: i32,
61 fitness: usize,
62 hyphenated: bool,
63 total_demerits: i32,
64 short: i32,
65 glue: i32,
66 },
67 Delta(Widths),
69}
70
71struct Item {
72 next: usize,
73 entry: Entry,
74}
75
76struct Passive {
78 cur_break: NodeRef,
79 prev_break: Option<usize>,
80 serial: i32,
81 left_pw: i32,
83}
84
85struct Breaker {
87 items: Vec<Item>,
88 free: Vec<usize>,
89 passive: Vec<Passive>,
90 active_width: Widths,
91 cur_active_width: Widths,
92 background: Widths,
93 break_width: Widths,
94 minimal_demerits: [i32; 4],
95 minimum_demerits: i32,
96 best_place: [Option<usize>; 4],
97 best_pl_line: [i32; 4],
98 best_pl_short: [i32; 4],
99 best_pl_glue: [i32; 4],
100 threshold: i32,
101 second_pass: bool,
102 final_pass: bool,
103 disc_width: i32,
104 disc_fs: crate::expansion::FontStretch,
106 easy_line: i32,
107 last_special_line: i32,
108 first_width: i32,
109 second_width: i32,
110 first_indent: i32,
111 second_indent: i32,
112 par_shape: Option<std::rc::Rc<[i32]>>,
113 printed_node: NodeRef,
114 pass_number: i32,
115 do_last_line_fit: bool,
116 fill_width: [i32; 4],
117 last_line_fit: i32,
118 adj_demerits: i32,
119 line_penalty: i32,
120 double_hyphen_demerits: i32,
121 final_hyphen_demerits: i32,
122 tracing: bool,
123 no_shrink_error_yet: bool,
124 protrude: bool,
126 first_left_pw: i32,
128 head: NodeRef,
130 expand: bool,
132 expand_kerns: bool,
134}
135
136const ACTIVE: usize = 0;
137
138impl Breaker {
139 fn alloc(&mut self, e: Entry, next: usize) -> usize {
140 if let Some(i) = self.free.pop() {
141 self.items[i] = Item { next, entry: e };
142 i
143 } else {
144 self.items.push(Item { next, entry: e });
145 self.items.len() - 1
146 }
147 }
148
149 fn release(&mut self, i: usize) {
150 self.free.push(i);
151 }
152
153 fn is_delta(&self, i: usize) -> bool {
154 matches!(self.items[i].entry, Entry::Delta(_))
155 }
156
157 fn delta(&self, i: usize) -> Widths {
158 match self.items[i].entry {
159 Entry::Delta(d) => d,
160 _ => [0; NW],
161 }
162 }
163
164 fn line_number(&self, i: usize) -> i32 {
165 match self.items[i].entry {
166 Entry::Active { line_number, .. } => line_number,
167 Entry::Sentinel => i32::MAX,
168 Entry::Delta(_) => 0,
169 }
170 }
171
172 fn clean_up(&mut self) {
174 self.items.truncate(1);
175 self.items[ACTIVE].next = ACTIVE;
176 self.free.clear();
177 self.passive.clear();
178 }
179}
180
181impl Engine {
182 fn disc_node_width(&self, s: NodeRef) -> i32 {
184 match self.nodes.data(s) {
185 NodeData::Glyph(_) => self.glyph_dimensions(s).0,
186 _ => self.nodes.width(s),
187 }
188 }
189
190 fn list_width(&self, mut s: NodeRef) -> i32 {
191 let mut w = 0;
192 while !s.is_null() {
193 w += self.disc_node_width(s);
194 s = self.nodes.next(s);
195 }
196 w
197 }
198
199 fn finite_shrink(&mut self, br: &mut Breaker, g: Glue) -> Glue {
201 if br.no_shrink_error_yet {
202 br.no_shrink_error_yet = false;
203 if br.tracing {
204 self.end_diagnostic(true);
205 }
206 self.print_err("Infinite glue shrinkage found in a paragraph");
207 self.help(&[
208 "The paragraph just ended includes some glue that has",
209 "infinite shrinkability, e.g., `\\hskip 0pt minus 1fil'.",
210 "Such glue doesn't belong there---it allows a paragraph",
211 "of any length to fit on one line. But it's safe to proceed,",
212 "since the offensive shrinkability has been made finite.",
213 ]);
214 self.error();
215 if br.tracing {
216 self.begin_diagnostic();
217 }
218 }
219 Glue {
220 shrink_order: 0,
221 ..g
222 }
223 }
224
225 pub fn line_break(&mut self, final_widow_penalty: i32) {
230 self.fonts.sync_dense();
231 let display = final_widow_penalty == self.eqtb.int(ip::DISPLAYWIDOWPENALTY)
232 && final_widow_penalty != self.eqtb.int(ip::WIDOWPENALTY);
233 self.ts.pack_begin_line = self.cur_list().mode_line;
234 let temp_head = self.nodes.new_temp();
237 let head = self.cur_list().head;
238 let first = self.nodes.next(head);
239 self.nodes.set_next(head, NodeRef::NULL);
240 let mut tail = self.cur_list().tail;
241 self.nodes.link(temp_head, first);
242 if tail == head {
243 tail = temp_head;
244 }
245 if self.nodes.id(tail) == id::GLUE {
246 let p = self.find_prev_in(temp_head, tail);
248 self.nodes.set_next(p, NodeRef::NULL);
249 self.nodes.flush_list(tail);
250 tail = p;
251 }
252 let pen = self.new_penalty_node(INF_PENALTY);
253 self.nodes.set_subtype(pen, 2);
255 self.nodes.link(tail, pen);
256 let pfs = self.new_param_glue(glue_sub::PAR_FILL_SKIP);
257 self.nodes.link(pen, pfs);
258 let last_line_fill = pfs;
259 self.pop_nest();
260 let first = self.nodes.next(temp_head);
262 let first = self.node_process_list(first, crate::nodeproc::Context::Paragraph);
263 let had_list = !first.is_null();
264 let first = self.filter_list("pre_linebreak_filter", first, "");
265 if had_list && first.is_null() {
266 self.confusion("weird par dir");
269 }
270 self.nodes.link(temp_head, first);
271 if first.is_null() {
272 self.nodes.set_next(temp_head, NodeRef::NULL);
273 }
274 let mut br = Breaker {
275 items: vec![Item {
276 next: ACTIVE,
277 entry: Entry::Sentinel,
278 }],
279 free: Vec::new(),
280 passive: Vec::new(),
281 active_width: [0; NW],
282 cur_active_width: [0; NW],
283 background: [0; NW],
284 break_width: [0; NW],
285 minimal_demerits: [AWFUL_BAD; 4],
286 minimum_demerits: AWFUL_BAD,
287 best_place: [None; 4],
288 best_pl_line: [0; 4],
289 best_pl_short: [0; 4],
290 best_pl_glue: [0; 4],
291 threshold: 0,
292 second_pass: false,
293 final_pass: false,
294 disc_width: 0,
295 disc_fs: Default::default(),
296 easy_line: 0,
297 last_special_line: 0,
298 first_width: 0,
299 second_width: 0,
300 first_indent: 0,
301 second_indent: 0,
302 par_shape: self.eqtb.par_shape.val.clone(),
303 printed_node: temp_head,
304 pass_number: 0,
305 do_last_line_fit: false,
306 fill_width: [0; 4],
307 last_line_fit: self.eqtb.int(ip::LASTLINEFIT),
308 adj_demerits: self.eqtb.int(ip::ADJDEMERITS),
309 line_penalty: self.eqtb.int(ip::LINEPENALTY),
310 double_hyphen_demerits: self.eqtb.int(ip::DOUBLEHYPHENDEMERITS),
311 final_hyphen_demerits: self.eqtb.int(ip::FINALHYPHENDEMERITS),
312 tracing: self.eqtb.int(ip::TRACINGPARAGRAPHS) > 0,
313 no_shrink_error_yet: true,
314 protrude: self.eqtb.int(ip::PROTRUDECHARS) > 1,
315 first_left_pw: 0,
316 head: temp_head,
317 expand: self.eqtb.int(ip::ADJUSTSPACING) > 1,
318 expand_kerns: self.eqtb.int(ip::ADJUSTSPACING) == 2,
319 };
320 if br.expand && !br.protrude {
321 self.fix_back_links(temp_head);
322 }
323 if br.protrude {
324 self.fix_back_links(temp_head);
325 let first = self.nodes.next(temp_head);
326 br.first_left_pw = self.lb_left_protrusion(None, first);
327 }
328 let mut ls = self.eqtb.glue(gp::LEFTSKIP);
329 let mut rs = self.eqtb.glue(gp::RIGHTSKIP);
330 if ls.shrink_order != 0 && ls.shrink != 0 {
331 ls = self.finite_shrink(&mut br, ls);
332 }
333 if rs.shrink_order != 0 && rs.shrink != 0 {
334 rs = self.finite_shrink(&mut br, rs);
335 }
336 br.background[0] = ls.width + rs.width;
337 br.background[1 + (ls.stretch_order as usize).min(4)] += ls.stretch;
338 br.background[1 + (rs.stretch_order as usize).min(4)] += rs.stretch;
339 br.background[6] = ls.shrink + rs.shrink;
340 if br.last_line_fit > 0 {
342 let q = self.nodes.glue_spec(last_line_fill);
343 if q.stretch > 0 && q.stretch_order > 0 && br.background[2..6].iter().all(|&v| v == 0) {
344 br.do_last_line_fit = true;
345 br.fill_width = [0; 4];
346 br.fill_width[(q.stretch_order as usize - 1).min(3)] = q.stretch;
347 }
348 }
349 let hsize = self.eqtb.dimen(dp::HSIZE);
351 let hang_indent = self.eqtb.dimen(dp::HANGINDENT);
352 let hang_after = self.eqtb.int(ip::HANGAFTER);
353 match &br.par_shape {
354 None => {
355 if hang_indent == 0 {
356 br.last_special_line = 0;
357 br.second_width = hsize;
358 br.second_indent = 0;
359 } else {
360 br.last_special_line = hang_after.abs();
361 if hang_after < 0 {
362 br.first_width = hsize - hang_indent.abs();
363 br.first_indent = hang_indent.max(0);
364 br.second_width = hsize;
365 br.second_indent = 0;
366 } else {
367 br.first_width = hsize;
368 br.first_indent = 0;
369 br.second_width = hsize - hang_indent.abs();
370 br.second_indent = hang_indent.max(0);
371 }
372 }
373 }
374 Some(s) => {
375 let n = (s.len() / 2) as i32;
376 br.last_special_line = n - 1;
377 br.second_indent = s[2 * (n as usize - 1)];
378 br.second_width = s[2 * (n as usize - 1) + 1];
379 }
380 }
381 br.easy_line = if self.eqtb.int(ip::LOOSENESS) == 0 {
382 br.last_special_line
383 } else {
384 i32::MAX - 1
385 };
386 br.threshold = self.eqtb.int(ip::PRETOLERANCE);
388 let emergency = self.eqtb.dimen(dp::EMERGENCYSTRETCH);
389 if br.threshold >= 0 {
390 if br.tracing {
391 self.begin_diagnostic();
392 self.printer.print_nl("@firstpass");
393 }
394 br.second_pass = false;
395 br.final_pass = false;
396 } else {
397 br.threshold = self.eqtb.int(ip::TOLERANCE);
398 br.second_pass = true;
399 br.final_pass = emergency <= 0;
400 if br.tracing {
401 self.begin_diagnostic();
402 }
403 }
404 let prev_graf = self.cur_list().prev_graf;
405 let looseness = self.eqtb.int(ip::LOOSENESS);
406 let best_bet: usize;
407 let best_line: i32;
408 loop {
409 if br.threshold > INF_BAD {
410 br.threshold = INF_BAD;
411 }
412 let q = br.alloc(
414 Entry::Active {
415 passive: None,
416 line_number: prev_graf + 1,
417 fitness: DECENT_FIT,
418 hyphenated: false,
419 total_demerits: 0,
420 short: 0,
421 glue: 0,
422 },
423 ACTIVE,
424 );
425 br.items[ACTIVE].next = q;
426 br.active_width = br.background;
427 br.passive.clear();
428 br.printed_node = temp_head;
429 br.pass_number = 0;
430 self.ts.font_in_short_display = 0;
431 let mut cur_p = self.nodes.next(temp_head);
432 let mut auto_breaking = true;
433 let mut prev_p = cur_p;
434 while !cur_p.is_null() && br.items[ACTIVE].next != ACTIVE {
435 let t = self.nodes.id(cur_p);
436 match t {
437 id::GLYPH => {
438 prev_p = cur_p;
440 while !cur_p.is_null() && self.nodes.id(cur_p) == id::GLYPH {
441 self.check_lost_char(cur_p);
442 br.active_width[0] += self.glyph_dimensions(cur_p).0;
443 if br.expand {
444 let f = self.glyph_font_stretch(cur_p);
445 br.active_width[FONT_STRETCH] += f.stretch;
446 br.active_width[FONT_SHRINK] += f.shrink;
447 }
448 cur_p = self.nodes.next(cur_p);
449 }
450 continue;
451 }
452 id::HLIST | id::VLIST | id::RULE => {
453 br.active_width[0] += self.nodes.width(cur_p);
454 }
455 id::GLUE => {
456 if auto_breaking {
457 let pt = self.nodes.id(prev_p);
458 let legal = pt == id::GLYPH
459 || crate::page::precedes_break(pt)
460 || (pt == id::KERN
461 && !matches!(
462 self.nodes.subtype(prev_p),
463 kern_sub::USER | kern_sub::ITALIC
464 ));
465 if legal {
466 self.try_break(&mut br, cur_p, 0, false);
467 }
468 }
469 let mut g = self.nodes.glue_spec(cur_p);
470 if g.shrink_order != 0 && g.shrink != 0 {
471 g = self.finite_shrink(&mut br, g);
472 if let NodeData::Glue { spec, .. } = self.nodes.data_mut(cur_p) {
473 *spec = g;
474 }
475 }
476 add_glue(&mut br.active_width, &g);
477 }
478 id::KERN => {
479 if matches!(self.nodes.subtype(cur_p), kern_sub::USER | kern_sub::ITALIC) {
480 self.kern_break(&mut br, cur_p, auto_breaking);
481 } else {
482 br.active_width[0] += self.nodes.width(cur_p);
483 if br.expand_kerns {
484 let (pv, nx) = (self.nodes.prev(cur_p), self.nodes.next(cur_p));
485 let f = self.kern_font_stretch(pv, cur_p, nx);
486 br.active_width[FONT_STRETCH] += f.stretch;
487 br.active_width[FONT_SHRINK] += f.shrink;
488 }
489 }
490 }
491 id::DISC => {
492 let (pre, _post, rep) = self.nodes.disc_lists(cur_p);
493 let pen = self.nodes.penalty(cur_p);
494 let from_hyphenation = self.nodes.subtype(cur_p) >= 3;
499 if br.second_pass || !from_hyphenation {
500 br.disc_width = self.list_width(pre);
501 br.active_width[0] += br.disc_width;
502 if br.expand {
503 br.disc_fs = self.list_font_stretch(pre, br.expand_kerns);
504 br.active_width[FONT_STRETCH] += br.disc_fs.stretch;
505 br.active_width[FONT_SHRINK] += br.disc_fs.shrink;
506 }
507 self.try_break(&mut br, cur_p, pen, true);
508 br.active_width[0] -= br.disc_width;
509 if br.expand {
510 br.active_width[FONT_STRETCH] -= br.disc_fs.stretch;
511 br.active_width[FONT_SHRINK] -= br.disc_fs.shrink;
512 }
513 }
514 br.active_width[0] += self.list_width(rep);
515 if br.expand {
516 let f = self.list_font_stretch(rep, br.expand_kerns);
517 br.active_width[FONT_STRETCH] += f.stretch;
518 br.active_width[FONT_SHRINK] += f.shrink;
519 }
520 }
521 id::MATH => {
522 auto_breaking = self.nodes.subtype(cur_p) == 1;
523 self.kern_break(&mut br, cur_p, auto_breaking);
524 }
525 id::PENALTY => {
526 let pen = self.nodes.penalty(cur_p);
527 self.try_break(&mut br, cur_p, pen, false);
528 }
529 id::MARGIN_KERN => {
530 br.active_width[0] += self.nodes.width(cur_p);
531 }
532 _ => {}
533 }
534 prev_p = cur_p;
535 cur_p = self.nodes.next(cur_p);
536 }
537 if cur_p.is_null() {
538 self.try_break(&mut br, NodeRef::NULL, EJECT_PENALTY, true);
540 if br.items[ACTIVE].next != ACTIVE {
541 let mut r = br.items[ACTIVE].next;
543 let mut fewest = AWFUL_BAD;
544 let mut bb = r;
545 while r != ACTIVE {
546 if let Entry::Active { total_demerits, .. } = br.items[r].entry
547 && total_demerits < fewest
548 {
549 fewest = total_demerits;
550 bb = r;
551 }
552 r = br.items[r].next;
553 }
554 let mut bl = br.line_number(bb);
555 if looseness == 0 {
556 best_bet = bb;
557 best_line = bl;
558 break;
559 }
560 let mut r = br.items[ACTIVE].next;
562 let mut actual = 0;
563 let mut bb2 = bb;
564 while r != ACTIVE {
565 if let Entry::Active {
566 line_number,
567 total_demerits,
568 ..
569 } = br.items[r].entry
570 {
571 let line_diff = line_number - bl;
572 if (line_diff < actual && looseness <= line_diff)
573 || (line_diff > actual && looseness >= line_diff)
574 {
575 bb2 = r;
576 actual = line_diff;
577 fewest = total_demerits;
578 } else if line_diff == actual && total_demerits < fewest {
579 bb2 = r;
580 fewest = total_demerits;
581 }
582 }
583 r = br.items[r].next;
584 }
585 bl = br.line_number(bb2);
586 if actual == looseness || br.final_pass {
587 best_bet = bb2;
588 best_line = bl;
589 break;
590 }
591 }
592 }
593 br.clean_up();
595 if !br.second_pass {
596 if br.tracing {
597 self.printer.print_nl("@secondpass");
598 }
599 br.threshold = self.eqtb.int(ip::TOLERANCE);
600 br.second_pass = true;
601 br.final_pass = emergency <= 0;
602 } else {
603 if br.tracing {
604 self.printer.print_nl("@emergencypass");
605 }
606 br.background[1] += emergency;
607 br.final_pass = true;
608 }
609 }
610 if br.tracing {
611 self.end_diagnostic(true);
612 self.normalize_selector();
613 }
614 if br.do_last_line_fit {
615 if let Entry::Active { short, glue, .. } = br.items[best_bet].entry {
617 if short == 0 {
618 br.do_last_line_fit = false;
619 } else if let NodeData::Glue { spec, .. } = self.nodes.data_mut(last_line_fill) {
620 spec.width += short - glue;
621 spec.stretch = 0;
622 }
623 }
624 }
625 let old_tail = self.cur_list().tail;
627 self.post_line_break(
628 &mut br,
629 best_bet,
630 best_line,
631 temp_head,
632 final_widow_penalty,
633 display,
634 );
635 if self.has_callback("post_linebreak_filter") {
636 let first = self.nodes.next(old_tail);
637 self.nodes.set_next(old_tail, NodeRef::NULL);
638 let first = self.filter_list("post_linebreak_filter", first, "");
639 self.cur_list_mut().tail = old_tail;
640 if !first.is_null() {
641 self.nodes.link(old_tail, first);
642 let t = self.nodes.tail_of(first);
643 self.cur_list_mut().tail = t;
644 }
645 }
646 br.clean_up();
647 self.nodes.free(temp_head);
648 self.ts.pack_begin_line = 0;
649 }
650
651 fn find_prev_in(&self, head: NodeRef, q: NodeRef) -> NodeRef {
652 let mut p = head;
653 loop {
654 let n = self.nodes.next(p);
655 if n == q || n.is_null() {
656 return p;
657 }
658 p = n;
659 }
660 }
661
662 fn kern_break(&mut self, br: &mut Breaker, cur_p: NodeRef, auto_breaking: bool) {
665 let n = self.nodes.next(cur_p);
666 if !n.is_null() && auto_breaking && self.nodes.id(n) == id::GLUE {
667 self.try_break(br, cur_p, 0, false);
668 }
669 br.active_width[0] += self.nodes.width(cur_p);
670 }
671
672 fn try_break(&mut self, br: &mut Breaker, cur_p: NodeRef, pi: i32, hyphenated: bool) {
674 let mut pi = pi;
675 if pi.abs() >= INF_PENALTY {
676 if pi > 0 {
677 return;
678 }
679 pi = EJECT_PENALTY;
680 }
681 let mut no_break_yet = true;
682 let mut prev_r = ACTIVE;
683 let mut prev_prev_r = ACTIVE;
684 let mut old_l = 0;
685 let mut line_width = 0;
686 let mut right_pw: Option<i32> = None;
687 br.cur_active_width = br.active_width;
688 loop {
689 let r = br.items[prev_r].next;
690 if let Entry::Delta(d) = br.items[r].entry {
692 for k in 0..NW {
693 br.cur_active_width[k] += d[k];
694 }
695 prev_prev_r = prev_r;
696 prev_r = r;
697 continue;
698 }
699 let l = br.line_number(r);
702 if l > old_l {
703 if br.minimum_demerits < AWFUL_BAD && (old_l != br.easy_line || r == ACTIVE) {
704 if no_break_yet {
705 no_break_yet = false;
706 self.compute_break_width(br, cur_p, hyphenated);
707 }
708 if br.is_delta(prev_r) {
710 let mut d = br.delta(prev_r);
711 for k in 0..NW {
712 d[k] = d[k] - br.cur_active_width[k] + br.break_width[k];
713 }
714 br.items[prev_r].entry = Entry::Delta(d);
715 } else if prev_r == ACTIVE {
716 br.active_width = br.break_width;
717 } else {
718 let mut d = [0; NW];
719 for k in 0..NW {
720 d[k] = br.break_width[k] - br.cur_active_width[k];
721 }
722 let q = br.alloc(Entry::Delta(d), r);
723 br.items[prev_r].next = q;
724 prev_prev_r = prev_r;
725 prev_r = q;
726 }
727 if br.adj_demerits.abs() >= AWFUL_BAD - br.minimum_demerits {
728 br.minimum_demerits = AWFUL_BAD - 1;
729 } else {
730 br.minimum_demerits += br.adj_demerits.abs();
731 }
732 for fit_class in VERY_LOOSE_FIT..=TIGHT_FIT {
733 if br.minimal_demerits[fit_class] <= br.minimum_demerits {
734 br.pass_number += 1;
736 let left_pw = if br.protrude {
737 self.lb_left_protrusion(Some(cur_p), NodeRef::NULL)
738 } else {
739 0
740 };
741 br.passive.push(Passive {
742 cur_break: cur_p,
743 prev_break: br.best_place[fit_class],
744 serial: br.pass_number,
745 left_pw,
746 });
747 let pidx = br.passive.len() - 1;
748 let (short, glue) = if br.do_last_line_fit {
749 (br.best_pl_short[fit_class], br.best_pl_glue[fit_class])
750 } else {
751 (0, 0)
752 };
753 let q = br.alloc(
754 Entry::Active {
755 passive: Some(pidx),
756 line_number: br.best_pl_line[fit_class] + 1,
757 fitness: fit_class,
758 hyphenated,
759 total_demerits: br.minimal_demerits[fit_class],
760 short,
761 glue,
762 },
763 r,
764 );
765 br.items[prev_r].next = q;
766 prev_r = q;
767 if br.tracing {
768 self.printer.print_nl("@@");
769 self.printer.print_int(i64::from(br.pass_number));
770 self.printer.print_str(": line ");
771 self.printer
772 .print_int(i64::from(br.best_pl_line[fit_class]));
773 self.printer.print_char('.' as u32);
774 self.printer.print_int(fit_class as i64);
775 if hyphenated {
776 self.printer.print_char('-' as u32);
777 }
778 self.printer.print_str(" t=");
779 self.printer
780 .print_int(i64::from(br.minimal_demerits[fit_class]));
781 if br.do_last_line_fit {
782 self.printer.print_str(" s=");
783 self.printer.print_scaled(short);
784 self.printer.print_str(if cur_p.is_null() {
785 " a="
786 } else {
787 " g="
788 });
789 self.printer.print_scaled(glue);
790 }
791 self.printer.print_str(" -> @");
792 match br.best_place[fit_class] {
793 None => self.printer.print_char('0' as u32),
794 Some(pp) => {
795 self.printer.print_int(i64::from(br.passive[pp].serial))
796 }
797 }
798 }
799 }
800 br.minimal_demerits[fit_class] = AWFUL_BAD;
801 }
802 br.minimum_demerits = AWFUL_BAD;
803 if r != ACTIVE {
805 let mut d = [0; NW];
806 for k in 0..NW {
807 d[k] = br.cur_active_width[k] - br.break_width[k];
808 }
809 let q = br.alloc(Entry::Delta(d), r);
810 br.items[prev_r].next = q;
811 prev_prev_r = prev_r;
812 prev_r = q;
813 }
814 }
815 if r == ACTIVE {
816 return;
817 }
818 if l > br.easy_line {
820 line_width = br.second_width;
821 old_l = i32::MAX - 1;
822 } else {
823 old_l = l;
824 line_width = if l > br.last_special_line {
825 br.second_width
826 } else {
827 match &br.par_shape {
828 None => br.first_width,
829 Some(s) => s[2 * (l as usize - 1) + 1],
830 }
831 };
832 }
833 }
834 let (r_passive, r_fitness, r_hyph, r_total, r_short, r_glue) = match br.items[r].entry {
836 Entry::Active {
837 passive,
838 fitness,
839 hyphenated,
840 total_demerits,
841 short,
842 glue,
843 ..
844 } => (passive, fitness, hyphenated, total_demerits, short, glue),
845 _ => (None, DECENT_FIT, false, 0, 0, 0),
846 };
847 let mut artificial_demerits = false;
848 let mut shortfall = line_width - br.cur_active_width[0];
849 if br.protrude {
850 let rp = *right_pw.get_or_insert_with(|| self.lb_right_protrusion(cur_p, br.head));
851 let lp = match r_passive {
852 Some(i) => br.passive[i].left_pw,
853 None => br.first_left_pw,
854 };
855 shortfall += lp + rp;
856 }
857 if br.expand {
858 let caw = &br.cur_active_width;
860 if shortfall > 0 && caw[FONT_STRETCH] > 0 {
861 shortfall = (shortfall - caw[FONT_STRETCH]).max(0);
862 } else if shortfall < 0 && caw[FONT_SHRINK] > 0 {
863 shortfall = (shortfall + caw[FONT_SHRINK]).min(0);
864 }
865 }
866 let mut g = 0i32;
867 let b: i32;
868 let fit_class: usize;
869 let caw = br.cur_active_width;
870 'found: {
871 if shortfall > 0 {
872 if caw[2] != 0 || caw[3] != 0 || caw[4] != 0 || caw[5] != 0 {
873 if br.do_last_line_fit {
874 if cur_p.is_null() {
875 'not_found: {
877 if r_short == 0 || r_glue <= 0 {
878 break 'not_found;
879 }
880 if caw[2] != br.fill_width[0]
881 || caw[3] != br.fill_width[1]
882 || caw[4] != br.fill_width[2]
883 || caw[5] != br.fill_width[3]
884 {
885 break 'not_found;
886 }
887 g = if r_short > 0 { caw[1] } else { caw[6] };
888 if g <= 0 {
889 break 'not_found;
890 }
891 let md = retex_arith::MAX_DIMEN;
892 g = match retex_arith::fract(g, r_short, r_glue, md) {
893 Ok(v) => v,
894 Err(_) => {
895 if r_short > 0 {
896 md
897 } else {
898 -md
899 }
900 }
901 };
902 if br.last_line_fit < 1000 {
903 g = retex_arith::fract(g, br.last_line_fit, 1000, md)
904 .unwrap_or(if r_short > 0 { md } else { -md });
905 }
906 if g > 0 {
907 if g > shortfall {
908 g = shortfall;
909 }
910 if g > 7_230_584 && caw[1] < 1_663_497 {
911 b = INF_BAD;
912 fit_class = VERY_LOOSE_FIT;
913 break 'found;
914 }
915 b = retex_arith::badness(g, caw[1]);
916 fit_class = if b > 12 {
917 if b > 99 { VERY_LOOSE_FIT } else { LOOSE_FIT }
918 } else {
919 DECENT_FIT
920 };
921 break 'found;
922 } else if g < 0 {
923 if -g > caw[6] {
924 g = -caw[6];
925 }
926 b = retex_arith::badness(-g, caw[6]);
927 fit_class = if b > 12 { TIGHT_FIT } else { DECENT_FIT };
928 break 'found;
929 }
930 }
931 }
932 shortfall = 0;
933 }
934 b = 0;
935 fit_class = DECENT_FIT;
936 } else if shortfall > 7_230_584 && caw[1] < 1_663_497 {
937 b = INF_BAD;
938 fit_class = VERY_LOOSE_FIT;
939 } else {
940 b = retex_arith::badness(shortfall, caw[1]);
941 fit_class = if b > 12 {
942 if b > 99 { VERY_LOOSE_FIT } else { LOOSE_FIT }
943 } else {
944 DECENT_FIT
945 };
946 }
947 } else {
948 b = if -shortfall > caw[6] {
949 INF_BAD + 1
950 } else {
951 retex_arith::badness(-shortfall, caw[6])
952 };
953 fit_class = if b > 12 { TIGHT_FIT } else { DECENT_FIT };
954 }
955 if br.do_last_line_fit {
956 if cur_p.is_null() {
958 shortfall = 0;
959 }
960 g = if shortfall > 0 {
961 caw[1]
962 } else if shortfall < 0 {
963 caw[6]
964 } else {
965 0
966 };
967 }
968 }
969 let node_r_stays_active;
970 let mut deactivate = false;
971 if b > INF_BAD || pi == EJECT_PENALTY {
972 if br.final_pass
973 && br.minimum_demerits == AWFUL_BAD
974 && br.items[r].next == ACTIVE
975 && prev_r == ACTIVE
976 {
977 artificial_demerits = true;
978 } else if b > br.threshold {
979 deactivate = true;
980 }
981 node_r_stays_active = false;
982 } else {
983 prev_r = r;
984 if b > br.threshold {
985 continue;
986 }
987 node_r_stays_active = true;
988 }
989 if !deactivate {
990 let mut d: i32;
992 if artificial_demerits {
993 d = 0;
994 } else {
995 d = br.line_penalty + b;
996 d = if d.abs() >= 10000 { 100_000_000 } else { d * d };
997 if pi != 0 {
998 if pi > 0 {
999 d += pi * pi;
1000 } else if pi > EJECT_PENALTY {
1001 d -= pi * pi;
1002 }
1003 }
1004 if hyphenated && r_hyph {
1005 if !cur_p.is_null() {
1006 d += br.double_hyphen_demerits;
1007 } else {
1008 d += br.final_hyphen_demerits;
1009 }
1010 }
1011 if (fit_class as i32 - r_fitness as i32).abs() > 1 {
1012 d += br.adj_demerits;
1013 }
1014 }
1015 if br.tracing {
1016 self.print_feasible_break(br, cur_p, r_passive, b, pi, d, artificial_demerits);
1017 }
1018 d += r_total;
1019 if d <= br.minimal_demerits[fit_class] {
1020 br.minimal_demerits[fit_class] = d;
1021 br.best_place[fit_class] = r_passive;
1022 br.best_pl_line[fit_class] = l;
1023 if br.do_last_line_fit {
1024 br.best_pl_short[fit_class] = shortfall;
1025 br.best_pl_glue[fit_class] = g;
1026 }
1027 if d < br.minimum_demerits {
1028 br.minimum_demerits = d;
1029 }
1030 }
1031 if node_r_stays_active {
1032 continue;
1033 }
1034 }
1035 let rn = br.items[r].next;
1037 br.items[prev_r].next = rn;
1038 br.release(r);
1039 if prev_r == ACTIVE {
1040 let r = br.items[ACTIVE].next;
1043 if let Entry::Delta(d) = br.items[r].entry {
1044 for k in 0..NW {
1045 br.active_width[k] += d[k];
1046 }
1047 br.cur_active_width = br.active_width;
1048 let rn = br.items[r].next;
1049 br.items[ACTIVE].next = rn;
1050 br.release(r);
1051 }
1052 } else if br.is_delta(prev_r) {
1053 let r = br.items[prev_r].next;
1054 if r == ACTIVE {
1055 let d = br.delta(prev_r);
1056 for k in 0..NW {
1057 br.cur_active_width[k] -= d[k];
1058 }
1059 br.items[prev_prev_r].next = ACTIVE;
1060 br.release(prev_r);
1061 prev_r = prev_prev_r;
1062 } else if let Entry::Delta(dr) = br.items[r].entry {
1063 let mut dp_ = br.delta(prev_r);
1064 for k in 0..NW {
1065 br.cur_active_width[k] += dr[k];
1066 dp_[k] += dr[k];
1067 }
1068 br.items[prev_r].entry = Entry::Delta(dp_);
1069 let rn = br.items[r].next;
1070 br.items[prev_r].next = rn;
1071 br.release(r);
1072 }
1073 }
1074 }
1075 }
1076
1077 fn compute_break_width(&mut self, br: &mut Breaker, cur_p: NodeRef, hyphenated: bool) {
1079 br.break_width = br.background;
1080 let mut s = cur_p;
1081 if hyphenated && !cur_p.is_null() && self.nodes.id(cur_p) == id::DISC {
1082 let (_pre, post, rep) = self.nodes.disc_lists(cur_p);
1083 br.break_width[0] -= self.list_width(rep);
1084 br.break_width[0] += self.list_width(post);
1085 br.break_width[0] += br.disc_width;
1086 if br.expand {
1087 let r = self.list_font_stretch(rep, br.expand_kerns);
1088 let p = self.list_font_stretch(post, br.expand_kerns);
1089 br.break_width[FONT_STRETCH] += p.stretch - r.stretch + br.disc_fs.stretch;
1090 br.break_width[FONT_SHRINK] += p.shrink - r.shrink + br.disc_fs.shrink;
1091 }
1092 s = if post.is_null() {
1093 self.nodes.next(cur_p)
1094 } else {
1095 NodeRef::NULL
1096 };
1097 }
1098 while !s.is_null() {
1099 match self.nodes.data(s) {
1100 NodeData::Glue { spec, .. } => {
1101 let g = *spec;
1102 br.break_width[0] -= g.width;
1103 br.break_width[1 + (g.stretch_order as usize).min(4)] -= g.stretch;
1104 br.break_width[6] -= g.shrink;
1105 }
1106 NodeData::Penalty { .. } => {}
1107 NodeData::Math { .. } => br.break_width[0] -= self.nodes.width(s),
1108 NodeData::Kern { kern, .. } => {
1109 if !matches!(self.nodes.subtype(s), kern_sub::USER | kern_sub::ITALIC) {
1110 break;
1111 }
1112 br.break_width[0] -= *kern;
1113 }
1114 _ => break,
1115 }
1116 s = self.nodes.next(s);
1117 }
1118 }
1119
1120 #[allow(clippy::too_many_arguments)]
1122 fn print_feasible_break(
1123 &mut self,
1124 br: &mut Breaker,
1125 cur_p: NodeRef,
1126 r_passive: Option<usize>,
1127 b: i32,
1128 pi: i32,
1129 d: i32,
1130 artificial: bool,
1131 ) {
1132 if br.printed_node != cur_p {
1133 self.printer.print_nl("");
1135 let start = self.nodes.next(br.printed_node);
1136 if cur_p.is_null() {
1137 self.short_display(start);
1138 } else {
1139 let save = self.nodes.next(cur_p);
1140 self.nodes.set_next(cur_p, NodeRef::NULL);
1141 self.printer.print_nl("");
1142 self.short_display(start);
1143 self.nodes.set_next(cur_p, save);
1144 }
1145 br.printed_node = cur_p;
1146 }
1147 self.printer.print_nl("@");
1148 if cur_p.is_null() {
1149 self.print_esc_str("par");
1150 } else {
1151 match self.nodes.id(cur_p) {
1152 id::GLUE => {}
1153 id::PENALTY => self.print_esc_str("penalty"),
1154 id::DISC => self.print_esc_str("discretionary"),
1155 id::KERN => self.print_esc_str("kern"),
1156 _ => self.print_esc_str("math"),
1157 }
1158 }
1159 self.printer.print_str(" via @");
1160 match r_passive {
1161 None => self.printer.print_char('0' as u32),
1162 Some(p) => self.printer.print_int(i64::from(br.passive[p].serial)),
1163 }
1164 self.printer.print_str(" b=");
1165 if b > INF_BAD {
1166 self.printer.print_char('*' as u32);
1167 } else {
1168 self.printer.print_int(i64::from(b));
1169 }
1170 self.printer.print_str(" p=");
1171 self.printer.print_int(i64::from(pi));
1172 self.printer.print_str(" d=");
1173 if artificial {
1174 self.printer.print_char('*' as u32);
1175 } else {
1176 self.printer.print_int(i64::from(d));
1177 }
1178 }
1179
1180 fn post_line_break(
1183 &mut self,
1184 br: &mut Breaker,
1185 best_bet: usize,
1186 best_line: i32,
1187 temp_head: NodeRef,
1188 final_widow_penalty: i32,
1189 display: bool,
1190 ) {
1191 let mut breaks: Vec<NodeRef> = Vec::new();
1193 let mut q = match br.items[best_bet].entry {
1194 Entry::Active { passive, .. } => passive,
1195 _ => None,
1196 };
1197 while let Some(i) = q {
1198 breaks.push(br.passive[i].cur_break);
1199 q = br.passive[i].prev_break;
1200 }
1201 breaks.reverse();
1202 let prev_graf = self.cur_list().prev_graf;
1203 let mut cur_line = prev_graf + 1;
1204 let ls = self.eqtb.glue(gp::LEFTSKIP);
1205 let ls_nonzero = ls.width != 0 || ls.stretch != 0 || ls.shrink != 0;
1206 let pardir = self.dir_param(crate::primitives_gen::assign_dir::PARDIR) as i8;
1207 let protrude = self.eqtb.int(ip::PROTRUDECHARS) > 0;
1208 let adjust_spacing = self.eqtb.int(ip::ADJUSTSPACING) > 0;
1209 let mut local_left = NodeRef::NULL;
1212 let mut local_right = NodeRef::NULL;
1213 let mut post_disc_break = false;
1214 let mut open_dirs: Vec<i8> = Vec::new();
1216 for (bi, &cb) in breaks.iter().enumerate() {
1217 let line_first = self.nodes.next(temp_head);
1219 if let Some((h, t)) = self.begin_dir_nodes(&open_dirs) {
1220 self.nodes.link(temp_head, h);
1221 self.nodes.link(t, line_first);
1222 if line_first.is_null() {
1223 self.nodes.set_next(t, NodeRef::NULL);
1224 }
1225 }
1226 self.track_open_dirs(line_first, cb, &mut open_dirs);
1227 {
1229 let mut s = self.nodes.next(temp_head);
1230 while !s.is_null() && s != cb {
1231 if let NodeData::LocalPar {
1232 box_left,
1233 box_right,
1234 ..
1235 } = self.nodes.data(s)
1236 {
1237 local_left = *box_left;
1238 local_right = *box_right;
1239 }
1240 s = self.nodes.next(s);
1241 }
1242 }
1243 let mut q = cb;
1246 let mut disc_break = false;
1247 post_disc_break = false;
1248 let mut rightskip_done = false;
1249 if !q.is_null() {
1250 match self.nodes.id(q) {
1251 id::GLUE => {
1252 let rs = self.eqtb.glue(gp::RIGHTSKIP);
1253 if let NodeData::Glue { spec, leader } = self.nodes.data_mut(q) {
1254 *spec = rs;
1255 let l = std::mem::take(leader);
1256 self.nodes.flush_list(l);
1257 }
1258 self.nodes.set_subtype(q, glue_sub::RIGHT_SKIP);
1259 rightskip_done = true;
1260 }
1261 id::DISC => {
1262 let (pre, post, rep) = self.nodes.disc_lists(q);
1266 self.nodes
1267 .set_disc_lists(q, (NodeRef::NULL, NodeRef::NULL, NodeRef::NULL));
1268 self.nodes.flush_list(rep);
1269 let r = self.nodes.next(q);
1270 if !post.is_null() {
1271 let t = self.nodes.tail_of(post);
1272 self.nodes.link(q, post);
1273 self.nodes.link(t, r);
1274 if r.is_null() {
1275 self.nodes.set_next(t, NodeRef::NULL);
1276 }
1277 post_disc_break = true;
1278 }
1279 if !pre.is_null() {
1280 let before = self.find_prev_in(temp_head, q);
1281 let t = self.nodes.tail_of(pre);
1282 self.nodes.link(before, pre);
1283 self.nodes.link(t, q);
1284 }
1285 disc_break = true;
1286 }
1287 id::KERN | id::MATH => match self.nodes.data_mut(q) {
1288 NodeData::Kern { kern, .. } => *kern = 0,
1289 NodeData::Math { surround, glue } => {
1290 *surround = 0;
1291 *glue = Glue::ZERO;
1292 }
1293 _ => {}
1294 },
1295 _ => {}
1296 }
1297 } else {
1298 q = self.nodes.tail_of(temp_head);
1299 }
1300 let q0 = q;
1301 if !rightskip_done {
1302 let r = self.new_param_glue(glue_sub::RIGHT_SKIP);
1303 if !q.is_null() && q != temp_head {
1305 let a = self.nodes.attr(q).cloned();
1306 self.nodes.set_attr(r, a);
1307 }
1308 let n = self.nodes.next(q);
1309 self.nodes.link(q, r);
1310 self.nodes.link(r, n);
1311 if n.is_null() {
1312 self.nodes.set_next(r, NodeRef::NULL);
1313 }
1314 q = r;
1315 }
1316 if let Some((h, t)) = self.end_dir_nodes(&open_dirs) {
1317 let mut at = q;
1321 if bi + 1 == breaks.len() {
1322 let p = self.find_prev_in(temp_head, q);
1323 if self.nodes.id(p) == id::GLUE
1324 && self.nodes.subtype(p) == glue_sub::PAR_FILL_SKIP
1325 {
1326 at = p;
1327 }
1328 }
1329 let p = self.find_prev_in(temp_head, at);
1330 self.nodes.link(p, h);
1331 self.nodes.link(t, at);
1332 }
1333 if !local_right.is_null() {
1334 let mut target = q;
1337 if bi + 1 == breaks.len() {
1338 let p = self.find_prev_in(temp_head, q);
1339 if self.nodes.id(p) == id::GLUE
1340 && self.nodes.subtype(p) == glue_sub::PAR_FILL_SKIP
1341 {
1342 target = p;
1343 }
1344 }
1345 let b = self.nodes.copy_node(local_right);
1346 let p = self.find_prev_in(temp_head, target);
1347 self.nodes.link(p, b);
1348 self.nodes.link(b, target);
1349 }
1350 if protrude {
1351 self.insert_right_margin_kern(temp_head, q0);
1352 }
1353 let r = self.nodes.next(q);
1355 self.nodes.set_next(q, NodeRef::NULL);
1356 let mut line = self.nodes.next(temp_head);
1357 self.nodes.set_next(temp_head, r);
1358 if !r.is_null() {
1359 self.nodes.set_prev(r, temp_head);
1360 }
1361 if !local_left.is_null() {
1362 let b = self.nodes.copy_node(local_left);
1363 self.nodes.link(b, line);
1364 line = b;
1365 }
1366 if protrude {
1367 let k = self.left_margin_kern(line);
1368 if !k.is_null() {
1369 self.nodes.link(k, line);
1370 line = k;
1371 }
1372 }
1373 if ls_nonzero {
1374 let g = self.new_param_glue(glue_sub::LEFT_SKIP);
1375 if !line.is_null() {
1377 let a = self.nodes.attr(line).cloned();
1378 self.nodes.set_attr(g, a);
1379 }
1380 self.nodes.link(g, line);
1381 line = g;
1382 }
1383 if !line.is_null() {
1384 self.nodes.set_prev(line, NodeRef::NULL);
1385 }
1386 let (cur_width, cur_indent) = if cur_line > br.last_special_line {
1388 (br.second_width, br.second_indent)
1389 } else {
1390 match &br.par_shape {
1391 None => (br.first_width, br.first_indent),
1392 Some(s) => (
1393 s[2 * (cur_line as usize - 1) + 1],
1394 s[2 * (cur_line as usize - 1)],
1395 ),
1396 }
1397 };
1398 self.start_adjust_lists();
1399 let natural = adjust_spacing && self.expand_line(line, cur_width);
1402 let just_box = if natural {
1403 let b = self.hpack(line, PackSpec::Additional(0));
1404 if let Some(bd) = self.nodes.box_data_mut(b) {
1405 bd.width = cur_width;
1406 }
1407 b
1408 } else {
1409 self.hpack(line, PackSpec::Exactly(cur_width))
1410 };
1411 self.ts.just_box = just_box;
1412 self.nodes.set_subtype(just_box, 1);
1413 if let Some(b) = self.nodes.box_data_mut(just_box) {
1414 b.shift = cur_indent;
1415 b.dir = pardir;
1416 }
1417 let pre_h = self.ts.pre_adjust_head;
1419 self.append_adjust_material(pre_h);
1420 self.append_to_vlist(just_box);
1421 let adj_h = self.ts.adjust_head;
1422 self.append_adjust_material(adj_h);
1423 self.ts.adjust_tail = None;
1424 self.ts.pre_adjust_tail = None;
1425 if cur_line + 1 != best_line {
1427 let mut pen = match &self.eqtb.etex_shape[es::INTERLINEPENALTIES as usize].val {
1428 Some(a) if !a.is_empty() => {
1429 let n = a.len() as i32;
1430 a[(cur_line.min(n) - 1).max(0) as usize]
1431 }
1432 _ => self.eqtb.int(ip::INTERLINEPENALTY),
1433 };
1434 match &self.eqtb.etex_shape[es::CLUBPENALTIES as usize].val {
1435 Some(a) if !a.is_empty() => {
1436 let n = a.len() as i32;
1437 let r = (cur_line - prev_graf).min(n);
1438 pen += a[(r - 1).max(0) as usize];
1439 }
1440 _ => {
1441 if cur_line == prev_graf + 1 {
1442 pen += self.eqtb.int(ip::CLUBPENALTY);
1443 }
1444 }
1445 }
1446 let wp_shape = if display {
1447 es::DISPLAYWIDOWPENALTIES
1448 } else {
1449 es::WIDOWPENALTIES
1450 };
1451 match &self.eqtb.etex_shape[wp_shape as usize].val {
1452 Some(a) if !a.is_empty() => {
1453 let n = a.len() as i32;
1454 let r = (best_line - cur_line - 1).min(n);
1455 pen += a[(r - 1).max(0) as usize];
1456 }
1457 _ => {
1458 if cur_line + 2 == best_line {
1459 pen += final_widow_penalty;
1460 }
1461 }
1462 }
1463 if disc_break {
1464 pen += self.eqtb.int(ip::BROKENPENALTY);
1465 }
1466 if pen != 0 {
1467 let r = self.new_penalty_node(pen);
1468 self.nodes.set_subtype(r, 1);
1470 self.tail_append(r);
1471 }
1472 }
1473 cur_line += 1;
1474 if bi + 1 < breaks.len() && !post_disc_break {
1476 let next_break = breaks[bi + 1];
1477 let mut r = temp_head;
1478 loop {
1479 let q = self.nodes.next(r);
1480 if q.is_null() || q == next_break {
1481 break;
1482 }
1483 let t = self.nodes.id(q);
1484 if t == id::GLYPH || crate::page::precedes_break(t) {
1485 break;
1486 }
1487 if t == id::KERN
1488 && !matches!(self.nodes.subtype(q), kern_sub::USER | kern_sub::ITALIC)
1489 {
1490 break;
1491 }
1492 if !matches!(t, id::GLUE | id::KERN | id::MATH | id::PENALTY) {
1493 break;
1494 }
1495 r = q;
1496 }
1497 if r != temp_head {
1498 let q = self.nodes.next(r);
1499 self.nodes.set_next(r, NodeRef::NULL);
1500 let first = self.nodes.next(temp_head);
1501 self.nodes.flush_list(first);
1502 self.nodes.link(temp_head, q);
1503 if q.is_null() {
1504 self.nodes.set_next(temp_head, NodeRef::NULL);
1505 }
1506 }
1507 }
1508 }
1509 let _ = post_disc_break;
1510 if !self.nodes.next(temp_head).is_null() {
1511 let rest = self.nodes.next(temp_head);
1513 self.nodes.set_next(temp_head, NodeRef::NULL);
1514 self.nodes.flush_list(rest);
1515 }
1516 self.cur_list_mut().prev_graf = best_line - 1;
1517 }
1518
1519 fn append_adjust_material(&mut self, head: NodeRef) {
1521 if head.is_null() {
1522 return;
1523 }
1524 let first = self.nodes.next(head);
1525 if first.is_null() {
1526 return;
1527 }
1528 let tail = self.cur_list().tail;
1529 self.nodes.link(tail, first);
1530 let t = self.nodes.tail_of(first);
1531 self.cur_list_mut().tail = t;
1532 self.nodes.set_next(head, NodeRef::NULL);
1533 }
1534}