1use crate::Engine;
34use crate::fonts::LigOp;
35use crate::nodes::{GlyphData, NodeData, NodeRef, glyph_sub, id, kern_sub};
36use crate::primitives_gen::assign_int as ip;
37
38#[derive(Clone, Copy, Debug, PartialEq, Eq)]
40pub enum Context {
41 Hbox,
43 Paragraph,
45}
46
47#[derive(Clone, Copy, Debug, PartialEq, Eq)]
49pub enum NodePass {
50 Hyphenate,
52 Ligaturing,
54 Kerning,
56}
57
58impl Engine {
59 pub fn lang_params(&self, l: u32) -> retex_hyph::Settings {
61 self.language(l).map(|x| x.settings).unwrap_or_default()
62 }
63
64 pub fn new_char_node(&mut self, f: u32, c: u32) -> NodeRef {
67 let lang = self.cur_lang() as u16;
68 let left = self.eqtb.int(ip::LEFTHYPHENMIN).clamp(0, 63) as u8;
69 let right = self.eqtb.int(ip::RIGHTHYPHENMIN).clamp(0, 63) as u8;
70 let uchyph = self.eqtb.int(ip::UCHYPH) > 0;
71 self.new_node(
72 id::GLYPH,
73 glyph_sub::CHARACTER,
74 NodeData::Glyph(GlyphData {
75 chr: c,
76 font: f,
77 lang,
78 left,
79 right,
80 uchyph,
81 ..GlyphData::default()
82 }),
83 )
84 }
85
86 pub fn node_process_list(&mut self, first: NodeRef, ctx: Context) -> NodeRef {
89 if first.is_null() {
90 return first;
91 }
92 self.fonts.sync_dense();
93 let head = self.nodes.new_temp();
94 self.nodes.link(head, first);
95 let saved_par_temp = self.nodes.par_temp;
96 if ctx == Context::Paragraph {
97 self.nodes.par_temp = head;
98 }
99 let host = self.lua.clone();
102 let pass = |e: &mut Engine, cb: &str| match &host {
103 Some(h) => {
104 if e.figures.recording() && h.has_callback(cb) {
105 e.figure_callback(cb);
106 }
107 h.node_pass(e, cb, head)
108 }
109 None => false,
110 };
111 if !pass(self, "hyphenate") {
112 self.hyphenate_list(head);
113 }
114 if !pass(self, "ligaturing") {
115 self.ligature_list(head, true);
116 }
117 if !pass(self, "kerning") {
118 self.kern_list(head);
119 }
120 self.nodes.par_temp = saved_par_temp;
121 let first = self.nodes.next(head);
122 if !first.is_null() {
123 self.nodes.set_prev(first, NodeRef::NULL);
124 }
125 self.nodes.free(head);
126 first
127 }
128
129 pub fn lua_node_pass(&mut self, pass: NodePass, head: NodeRef) -> (NodeRef, NodeRef) {
134 if head.is_null() {
135 return (head, head);
136 }
137 self.fonts.sync_dense();
138 let temp = self.nodes.id(head) == id::TEMP;
139 let h = if temp {
140 head
141 } else {
142 let t = self.nodes.new_temp();
143 self.nodes.link(t, head);
144 t
145 };
146 match pass {
147 NodePass::Hyphenate => self.hyphenate_list(h),
148 NodePass::Ligaturing => self.ligature_list(h, true),
149 NodePass::Kerning => self.kern_list(h),
150 }
151 let first = if temp {
152 head
153 } else {
154 let f = self.nodes.next(h);
155 if !f.is_null() {
156 self.nodes.set_prev(f, NodeRef::NULL);
157 }
158 self.nodes.free(h);
159 f
160 };
161 let tail = self.nodes.tail_of(first);
162 (first, tail)
163 }
164
165 fn hyphenate_list(&mut self, head: NodeRef) {
171 let ex = self.eqtb.int(ip::EXHYPHENCHAR);
172 let pen = self.eqtb.int(ip::EXHYPHENPENALTY);
173 if ex > 0 {
174 let ex = ex as u32;
175 let is_hyphen = |e: &Engine, n: NodeRef| e.nodes.glyph(n).is_some_and(|g| g.chr == ex);
176 let mut armed = true;
179 let mut prev = head;
180 let mut p = self.nodes.next(head);
181 while !p.is_null() {
182 if self.nodes.id(p) == id::MATH && self.nodes.subtype(p) == 0 {
185 let mut q = self.nodes.next(p);
186 while !(q.is_null()
187 || (self.nodes.id(q) == id::MATH && self.nodes.subtype(q) == 1))
188 {
189 q = self.nodes.next(q);
190 }
191 if q.is_null() {
192 break;
193 }
194 prev = q;
195 p = self.nodes.next(q);
196 continue;
197 }
198 if !is_hyphen(self, p) {
199 match self.nodes.id(p) {
200 id::GLUE => armed = true,
201 id::KERN => armed = false,
202 _ => {}
203 }
204 prev = p;
205 p = self.nodes.next(p);
206 continue;
207 }
208 let mut last = p;
210 let mut len = 1;
211 let mut q = self.nodes.next(p);
212 while !q.is_null() && is_hyphen(self, q) {
213 last = q;
214 len += 1;
215 q = self.nodes.next(q);
216 }
217 let followed = !q.is_null() && self.nodes.is_glyph(q);
218 let convert =
219 followed && (len == 1 || (armed && prev != head && self.has_hj_code(prev)));
220 if !convert {
221 prev = last;
222 p = q;
223 continue;
224 }
225 if len > 1 {
226 armed = false;
227 }
228 let before = if len == 1 {
230 prev
231 } else {
232 self.nodes.prev(last)
233 };
234 self.nodes.set_next(last, NodeRef::NULL);
235 let d = self.nodes.new_disc(2, pen);
236 if let Some(a) = self.nodes.attr(last).cloned() {
237 self.nodes.set_attr(d, Some(a));
238 }
239 let pre = self.nodes.copy_list(last);
240 self.nodes.set_prev(last, NodeRef::NULL);
241 self.nodes.set_disc_lists(d, (pre, NodeRef::NULL, last));
242 self.nodes.link(before, d);
243 self.nodes.link(d, q);
244 prev = d;
245 p = q;
246 }
247 }
248 if !self.languages.is_empty() {
249 self.pattern_hyphenate(head);
250 }
251 }
252
253 fn has_hj_code(&self, p: NodeRef) -> bool {
256 let Some(g) = self.nodes.glyph(p) else {
257 return false;
258 };
259 let lang = u32::from(g.lang);
260 let c = g.chr;
261 let code = match self.language(lang) {
262 Some(l) if l.has_hj_codes() => l.hj_code(c),
263 _ => self.eqtb.lc.get(c).max(0) as u32,
264 };
265 code != 0
266 }
267
268 fn pattern_hyphenate(&mut self, head: NodeRef) {
287 let hpen = self.eqtb.int(ip::HYPHENPENALTY);
288 let auto_ok = self.eqtb.int(ip::AUTOMATICHYPHENMODE) != 0;
289 let mut run: Vec<NodeRef> = Vec::new();
290 let mut word: Vec<NodeRef> = Vec::new();
291 let mut codes: Vec<u32> = Vec::new();
292 let mut pos: Vec<usize> = Vec::new();
293 let mut can_start = true;
294 let mut seen_glyph = false;
295 let mut skip_first = false;
298 let mut unit_kill: Option<bool> = None;
301 let mut p = self.nodes.next(head);
302 while !p.is_null() {
303 if self.nodes.is_glyph(p) && self.nodes.subtype(p) & glyph_sub::CHARACTER != 0 {
304 run.clear();
306 let mut q = p;
307 while !q.is_null()
308 && self.nodes.is_glyph(q)
309 && self.nodes.subtype(q) & glyph_sub::CHARACTER != 0
310 {
311 run.push(q);
312 q = self.nodes.next(q);
313 }
314 let end_ok = q.is_null()
315 || match self.nodes.id(q) {
316 id::DISC => auto_ok && self.nodes.subtype(q) == 2,
317 id::MATH | id::MARK => false,
318 _ => true,
319 };
320 let kill = *unit_kill.get_or_insert_with(|| self.unit_ends_badly(q));
321 let bounds = (can_start && !kill, end_ok, skip_first);
322 self.hyphenate_run(&run, hpen, bounds, &mut word, &mut codes, &mut pos);
323 seen_glyph = true;
324 skip_first = false;
325 p = q;
326 continue;
327 }
328 if !(self.nodes.id(p) == id::DISC && self.nodes.subtype(p) == 2) {
329 unit_kill = None;
330 }
331 if self.nodes.id(p) == id::MATH && self.nodes.subtype(p) == 0 {
335 let mut q = self.nodes.next(p);
336 while !(q.is_null() || (self.nodes.id(q) == id::MATH && self.nodes.subtype(q) == 1))
337 {
338 q = self.nodes.next(q);
339 }
340 p = if q.is_null() { q } else { self.nodes.next(q) };
341 continue;
342 }
343 match self.nodes.id(p) {
344 id::GLUE => can_start = true,
345 id::KERN | id::PENALTY | id::MARK | id::ADJUST => can_start &= !seen_glyph,
346 id::DISC if auto_ok && self.nodes.subtype(p) == 2 => can_start = true,
347 id::DISC if self.nodes.subtype(p) == 2 && self.single_hyphen_disc(p) => {
348 can_start = true;
349 skip_first = true;
350 }
351 id::DISC => can_start &= !seen_glyph,
352 _ => {}
353 }
354 p = self.nodes.next(p);
355 }
356 }
357
358 fn single_hyphen_disc(&self, d: NodeRef) -> bool {
361 let ex = self.eqtb.int(ip::EXHYPHENCHAR);
362 let prev = self.nodes.prev(d);
363 !prev.is_null()
364 && self
365 .nodes
366 .glyph(prev)
367 .is_some_and(|g| ex <= 0 || g.chr != ex as u32)
368 }
369
370 fn unit_ends_badly(&self, mut q: NodeRef) -> bool {
374 loop {
375 if q.is_null() {
376 return false;
377 }
378 match self.nodes.id(q) {
379 id::DISC if self.nodes.subtype(q) == 2 => {}
380 id::DISC | id::MATH | id::MARK => return true,
381 _ if self.nodes.is_glyph(q)
382 && self.nodes.subtype(q) & glyph_sub::CHARACTER != 0 => {}
383 _ => return false,
384 }
385 q = self.nodes.next(q);
386 }
387 }
388
389 fn hyphenate_run(
392 &mut self,
393 run: &[NodeRef],
394 hpen: i32,
395 bounds: (bool, bool, bool),
396 word: &mut Vec<NodeRef>,
397 codes: &mut Vec<u32>,
398 pos: &mut Vec<usize>,
399 ) {
400 if !bounds.0 {
401 return;
402 }
403 let mut i = 0;
404 while i < run.len() {
405 let Some(g0) = self.nodes.glyph(run[i]).cloned() else {
407 i += 1;
408 continue;
409 };
410 let lang = u32::from(g0.lang);
411 word.clear();
412 codes.clear();
413 let ex = self.eqtb.int(ip::EXHYPHENCHAR);
417 let mut with_hyphen = false;
418 while i < run.len() {
419 let Some(g) = self.nodes.glyph(run[i]) else {
420 break;
421 };
422 if u32::from(g.lang) != lang {
423 break;
424 }
425 let c = g.chr;
426 let code = match self.language(lang) {
427 Some(l) if l.has_hj_codes() => l.hj_code(c),
428 _ => self.eqtb.lc.get(c).max(0) as u32,
429 };
430 if code == 0 {
431 if word.is_empty() {
432 with_hyphen = ex > 0 && c == ex as u32;
433 i += 1;
434 continue;
435 }
436 with_hyphen |= ex > 0 && c == ex as u32;
437 break;
438 }
439 with_hyphen |= ex > 0 && c == ex as u32;
440 word.push(run[i]);
441 codes.push(code);
442 i += 1;
443 }
444 if word.len() < 2 || with_hyphen || (bounds.2 && word.first() == run.first()) {
445 continue;
446 }
447 if !bounds.1 && word.last() == run.last() {
448 continue;
449 }
450 let Some(first) = self.nodes.glyph(word[0]).cloned() else {
451 continue;
452 };
453 if first.font == 0 || self.font(first.font).hyphen_char < 0 {
454 continue;
455 }
456 if !first.uchyph && codes[0] != first.chr {
457 continue;
458 }
459 let Some(language) = self.language(lang) else {
460 continue;
461 };
462 pos.clear();
463 let _ =
464 language.hyphenate_into(codes, u32::from(first.left), u32::from(first.right), pos);
465 if pos.is_empty() {
466 continue;
467 }
468 let settings = language.settings;
469 pos.sort_unstable();
470 pos.dedup();
471 for &k in pos.iter().rev() {
472 if k == 0 || k >= word.len() {
473 continue;
474 }
475 let left = word[k - 1];
476 let right = word[k];
477 let f = self.nodes.glyph(left).map_or(0, |g| g.font);
478 let d = self.nodes.new_disc(3, hpen);
479 if let Some(a) = self.nodes.attr(left).cloned() {
480 self.nodes.set_attr(d, Some(a));
481 }
482 let mk = |e: &mut Engine, c: i32| {
483 if c > 0 {
484 let mut g = e.nodes.glyph(left).cloned().unwrap_or_default();
485 g.chr = c as u32;
486 g.font = f;
487 g.components = NodeRef::NULL;
488 let a = e.nodes.attr(left).cloned();
491 let n = e
492 .nodes
493 .alloc(id::GLYPH, glyph_sub::CHARACTER, NodeData::Glyph(g));
494 e.nodes.set_attr(n, a);
495 n
496 } else {
497 NodeRef::NULL
498 }
499 };
500 let pre = mk(self, settings.pre_hyphen_char);
501 let post = mk(self, settings.post_hyphen_char);
502 self.nodes.set_disc_lists(d, (pre, post, NodeRef::NULL));
503 self.nodes.link(left, d);
504 self.nodes.link(d, right);
505 }
506 }
507 }
508
509 #[inline]
513 fn glyph_of_font(&self, p: NodeRef, f: u32) -> Option<u32> {
514 if p.is_null() {
515 return None;
516 }
517 match self.nodes.data(p) {
518 NodeData::Glyph(g) if g.font == f && self.nodes.subtype(p) & glyph_sub::GHOST == 0 => {
519 Some(g.chr)
520 }
521 _ => None,
522 }
523 }
524
525 #[inline]
528 fn lig_step(&self, f: u32, l: u32, r: u32) -> Option<(u8, u32)> {
529 if self.font(f).ignore_ligatures != 0 {
530 return None;
531 }
532 match self.lig_kern_step(f, l, r) {
533 Some(LigOp::Lig { op, chr }) => Some((op, chr)),
534 _ => None,
535 }
536 }
537
538 fn take_components(&mut self, p: NodeRef) -> NodeRef {
541 let is_lig = self.nodes.subtype(p) & glyph_sub::LIGATURE != 0;
542 if is_lig {
543 let c = self
544 .nodes
545 .glyph_mut(p)
546 .map(|g| std::mem::take(&mut g.components));
547 let c = c.unwrap_or(NodeRef::NULL);
548 self.nodes.free(p);
549 if c.is_null() {
550 return NodeRef::NULL;
551 }
552 c
553 } else {
554 self.nodes.set_next(p, NodeRef::NULL);
555 self.nodes.set_prev(p, NodeRef::NULL);
556 let s = self.nodes.subtype(p) & !glyph_sub::CHARACTER;
557 self.nodes.set_subtype(p, s);
558 p
559 }
560 }
561
562 fn new_ligature(&mut self, model: NodeRef, c: u32, comps: NodeRef) -> NodeRef {
565 let mut g = self.nodes.glyph(model).cloned().unwrap_or_default();
566 g.chr = c;
567 g.components = comps;
568 let a = self.nodes.attr(model).cloned();
569 let n = self
570 .nodes
571 .alloc(id::GLYPH, glyph_sub::LIGATURE, NodeData::Glyph(g));
572 self.nodes.set_attr(n, a);
573 n
574 }
575
576 fn concat(&mut self, a: NodeRef, b: NodeRef) -> NodeRef {
578 if a.is_null() {
579 return b;
580 }
581 if !b.is_null() {
582 let t = self.nodes.tail_of(a);
583 self.nodes.link(t, b);
584 }
585 a
586 }
587
588 fn replace_node(&mut self, prev: NodeRef, old_next: NodeRef, new: NodeRef) {
590 self.nodes.link(prev, new);
591 self.nodes.link(new, old_next);
592 if old_next.is_null() {
593 self.nodes.set_next(new, NodeRef::NULL);
594 }
595 }
596
597 fn ligature_list(&mut self, head: NodeRef, main: bool) {
600 let mut prev = head;
601 let mut p = self.nodes.next(head);
602 while !p.is_null() {
603 match self.nodes.id(p) {
604 id::BOUNDARY if main => {
605 let n = self.nodes.next(p);
606 self.nodes.set_next(prev, n);
607 if !n.is_null() {
608 self.nodes.set_prev(n, prev);
609 }
610 self.nodes.free(p);
611 p = n;
612 }
613 id::GLYPH => {
614 let (last_prev, last) = self.ligature_run(prev, p);
615 let n = self.nodes.next(last);
618 if main
619 && (n.is_null()
620 || !matches!(self.nodes.id(n), id::GLYPH | id::DISC | id::BOUNDARY))
621 {
622 self.right_boundary_kern(last);
623 }
624 if !n.is_null() && self.nodes.id(n) == id::DISC {
625 let (np, nd) = self.lig_disc(last_prev, last, n);
626 prev = np;
627 p = nd;
628 } else {
629 prev = last;
630 p = n;
631 }
632 }
633 id::DISC => {
634 self.lig_disc_lists(p);
635 prev = p;
636 p = self.nodes.next(p);
637 }
638 _ => {
639 prev = p;
640 p = self.nodes.next(p);
641 }
642 }
643 }
644 }
645
646 fn right_boundary_kern(&mut self, p: NodeRef) {
652 let Some((f, l)) = self.nodes.glyph(p).map(|g| (g.font, g.chr)) else {
653 return;
654 };
655 let Some(b) = self.font(f).right_boundary else {
656 return;
657 };
658 if let Some(k) = self.kern_between(f, l, b) {
659 let kn = self.font_kern(k, p);
660 let n = self.nodes.next(p);
661 self.nodes.link(p, kn);
662 self.nodes.link(kn, n);
663 }
664 }
665
666 fn lig_disc_lists(&mut self, d: NodeRef) {
668 let (pre, post, rep) = self.nodes.disc_lists(d);
669 let pre = self.ligature_sublist(pre);
670 let post = self.ligature_sublist(post);
671 let rep = self.ligature_sublist(rep);
672 self.nodes.set_disc_lists(d, (pre, post, rep));
673 }
674
675 fn ligature_sublist(&mut self, l: NodeRef) -> NodeRef {
677 if l.is_null() {
678 return l;
679 }
680 let h = self.nodes.new_temp();
681 self.nodes.link(h, l);
682 self.ligature_list(h, false);
683 let r = self.nodes.next(h);
684 if !r.is_null() {
685 self.nodes.set_prev(r, NodeRef::NULL);
686 }
687 self.nodes.free(h);
688 r
689 }
690
691 fn lig_disc(&mut self, before: NodeRef, last: NodeRef, d: NodeRef) -> (NodeRef, NodeRef) {
696 let f = self.nodes.glyph(last).map_or(0, |g| g.font);
697 if self.font(f).lig_kern.is_empty() {
698 self.lig_disc_lists(d);
699 return (d, self.nodes.next(d));
700 }
701 let lc = self.nodes.glyph(last).map_or(0, |g| g.chr);
702 let (pre, post, rep) = self.nodes.disc_lists(d);
703 let after = self.nodes.next(d);
704 let crosses =
705 |e: &Engine, l: NodeRef| e.glyph_of_font(l, f).and_then(|c| e.lig_step(f, lc, c));
706 let left = crosses(self, pre).is_some()
707 || (!rep.is_null() && crosses(self, rep).is_some())
708 || (rep.is_null() && crosses(self, after).is_some());
709 let (mut pre, mut post, mut rep) = (pre, post, rep);
710 if left {
711 self.nodes.link(before, d);
713 self.nodes.set_next(last, NodeRef::NULL);
714 self.nodes.set_prev(last, NodeRef::NULL);
715 let copy = self.nodes.copy_node(last);
716 pre = self.concat(copy, pre);
717 rep = self.concat(last, rep);
718 }
719 loop {
722 let n = self.nodes.next(d);
723 let Some(nc) = self.glyph_of_font(n, f) else {
724 break;
725 };
726 let ends = |e: &Engine, l: NodeRef| {
727 if l.is_null() {
728 return false;
729 }
730 let t = e.nodes.tail_of(l);
731 e.glyph_of_font(t, f)
732 .is_some_and(|c| e.lig_step(f, c, nc).is_some())
733 };
734 if !(ends(self, post) || ends(self, rep)) {
735 break;
736 }
737 let nn = self.nodes.next(n);
738 self.nodes.link(d, nn);
739 if nn.is_null() {
740 self.nodes.set_next(d, NodeRef::NULL);
741 }
742 self.nodes.set_next(n, NodeRef::NULL);
743 self.nodes.set_prev(n, NodeRef::NULL);
744 let copy = self.nodes.copy_node(n);
745 post = self.concat(post, copy);
746 rep = self.concat(rep, n);
747 }
748 self.nodes.set_disc_lists(d, (pre, post, rep));
749 self.lig_disc_lists(d);
750 (d, self.nodes.next(d))
751 }
752
753 fn ligature_run(&mut self, prev: NodeRef, p: NodeRef) -> (NodeRef, NodeRef) {
757 let f = self.nodes.glyph(p).map_or(0, |g| g.font);
758 if self.font(f).lig_kern.is_empty() {
759 let (mut qp, mut q) = (prev, p);
761 loop {
762 let n = self.nodes.next(q);
763 if self.glyph_of_font(n, f).is_none() {
764 return (qp, q);
765 }
766 qp = q;
767 q = n;
768 }
769 }
770 let mut cur_prev = prev;
771 let mut cur = p;
772 let mut guard = 0u32;
773 loop {
774 let nxt = self.nodes.next(cur);
775 let (Some(l), Some(r)) = (self.glyph_of_font(cur, f), self.glyph_of_font(nxt, f))
776 else {
777 return (cur_prev, cur);
778 };
779 guard += 1;
780 if guard > 100_000 {
781 return (cur_prev, cur);
783 }
784 let Some((op, c)) = self.lig_step(f, l, r) else {
785 cur_prev = cur;
786 cur = nxt;
787 continue;
788 };
789 let after = self.nodes.next(nxt);
790 match op {
791 0 => {
792 let a = self.take_components(cur);
794 let b = self.take_components(nxt);
795 let comps = self.concat(a, b);
796 let model = if comps.is_null() { cur } else { comps };
797 let lig = self.new_ligature(model, c, comps);
798 self.replace_node(cur_prev, after, lig);
799 cur = lig;
800 }
801 1 | 5 => {
802 let a = self.take_components(cur);
804 let model = if a.is_null() { nxt } else { a };
805 let lig = self.new_ligature(model, c, a);
806 self.replace_node(cur_prev, nxt, lig);
807 if op == 5 {
808 cur_prev = lig;
809 cur = nxt;
810 } else {
811 cur = lig;
812 }
813 }
814 2 | 6 => {
815 let b = self.take_components(nxt);
817 let model = if b.is_null() { cur } else { b };
818 let lig = self.new_ligature(model, c, b);
819 self.replace_node(cur, after, lig);
820 if op == 6 {
821 cur_prev = cur;
822 cur = lig;
823 }
824 }
825 _ => {
826 let lig = self.new_ligature(cur, c, NodeRef::NULL);
828 self.nodes.set_subtype(lig, 0);
829 self.replace_node(cur, nxt, lig);
830 match op {
831 7 => {
832 cur_prev = cur;
833 cur = lig;
834 }
835 11 => {
836 cur_prev = lig;
837 cur = nxt;
838 }
839 _ => {}
840 }
841 }
842 }
843 }
844 }
845
846 #[inline]
850 fn kern_between(&self, f: u32, l: u32, r: u32) -> Option<i32> {
851 match self.lig_kern_step(f, l, r) {
852 Some(LigOp::Kern(k)) => Some(k),
853 _ => None,
854 }
855 }
856
857 fn font_kern(&mut self, k: i32, model: NodeRef) -> NodeRef {
859 let n = self.nodes.new_kern(k, kern_sub::FONT);
860 let a = self.nodes.attr(model).cloned();
861 self.nodes.set_attr(n, a);
862 n
863 }
864
865 fn kern_list(&mut self, head: NodeRef) {
868 let mut p = self.nodes.next(head);
869 while !p.is_null() {
870 match self.nodes.id(p) {
871 id::GLYPH => {
872 let s = self.nodes.subtype(p) & !glyph_sub::CHARACTER;
873 self.nodes.set_subtype(p, s);
874 let n = self.nodes.next(p);
875 if n.is_null() {
876 break;
877 }
878 let (f, l) = match self.nodes.glyph(p) {
879 Some(g) => (g.font, g.chr),
880 None => break,
881 };
882 if self.nodes.id(n) == id::GLYPH {
883 if let Some(r) = self.glyph_of_font(n, f)
884 && let Some(k) = self.kern_between(f, l, r)
885 {
886 let kn = self.font_kern(k, p);
887 self.nodes.link(p, kn);
888 self.nodes.link(kn, n);
889 }
890 p = n;
891 } else if self.nodes.id(n) == id::DISC {
892 self.kern_disc(p, n);
893 p = self.nodes.next(n);
894 } else {
895 p = n;
896 }
897 }
898 id::DISC => {
899 self.kern_disc(NodeRef::NULL, p);
900 p = self.nodes.next(p);
901 }
902 _ => p = self.nodes.next(p),
903 }
904 }
905 }
906
907 fn kern_disc(&mut self, before: NodeRef, d: NodeRef) {
910 let (mut pre, mut post, mut rep) = self.nodes.disc_lists(d);
911 pre = self.kern_sublist(pre);
912 post = self.kern_sublist(post);
913 let rep_was_empty = rep.is_null();
914 rep = self.kern_sublist(rep);
915 let after = self.nodes.next(d);
916 let bg = if before.is_null() {
917 None
918 } else {
919 self.nodes.glyph(before).map(|g| (g.font, g.chr))
920 };
921 let ag = if after.is_null() || self.nodes.id(after) != id::GLYPH {
922 None
923 } else {
924 self.nodes.glyph(after).map(|g| (g.font, g.chr))
925 };
926 let sub = self.nodes.subtype(d);
931 let left_kerns = !matches!(sub, 2 | 3);
932 if let Some((f, l)) = bg {
933 if left_kerns
934 && let Some(r) = self.glyph_of_font(pre, f)
935 && let Some(k) = self.kern_between(f, l, r)
936 {
937 let kn = self.font_kern(k, before);
938 self.nodes.link(kn, pre);
939 pre = kn;
940 }
941 if sub == 2 {
942 } else if !rep_was_empty {
944 if let Some(r) = self.glyph_of_font(rep, f)
945 && let Some(k) = self.kern_between(f, l, r)
946 {
947 let kn = self.font_kern(k, before);
948 self.nodes.link(kn, rep);
949 rep = kn;
950 }
951 } else if let Some((af, ac)) = ag
952 && af == f
953 && let Some(k) = self.kern_between(f, l, ac)
954 {
955 rep = self.font_kern(k, before);
956 }
957 }
958 if let Some((f, r)) = ag {
959 if !post.is_null() {
960 let t = self.nodes.tail_of(post);
961 if let Some(l) = self.glyph_of_font(t, f)
962 && let Some(k) = self.kern_between(f, l, r)
963 {
964 let kn = self.font_kern(k, after);
965 self.nodes.link(t, kn);
966 }
967 }
968 if !rep_was_empty {
969 let t = self.nodes.tail_of(rep);
970 if let Some(l) = self.glyph_of_font(t, f)
971 && let Some(k) = self.kern_between(f, l, r)
972 {
973 let kn = self.font_kern(k, after);
974 self.nodes.link(t, kn);
975 }
976 }
977 }
978 self.nodes.set_disc_lists(d, (pre, post, rep));
979 }
980
981 fn kern_sublist(&mut self, l: NodeRef) -> NodeRef {
983 if l.is_null() {
984 return l;
985 }
986 let h = self.nodes.new_temp();
987 self.nodes.link(h, l);
988 self.kern_list(h);
989 let r = self.nodes.next(h);
990 if !r.is_null() {
991 self.nodes.set_prev(r, NodeRef::NULL);
992 }
993 self.nodes.free(h);
994 r
995 }
996}