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
47impl Engine {
48 pub fn lang_params(&self, l: u32) -> retex_hyph::Settings {
50 self.language(l).map(|x| x.settings).unwrap_or_default()
51 }
52
53 pub fn new_char_node(&mut self, f: u32, c: u32) -> NodeRef {
56 let lang = self.cur_lang() as u16;
57 let left = self.eqtb.int(ip::LEFTHYPHENMIN).clamp(0, 63) as u8;
58 let right = self.eqtb.int(ip::RIGHTHYPHENMIN).clamp(0, 63) as u8;
59 let uchyph = self.eqtb.int(ip::UCHYPH) > 0;
60 self.new_node(
61 id::GLYPH,
62 glyph_sub::CHARACTER,
63 NodeData::Glyph(GlyphData {
64 chr: c,
65 font: f,
66 lang,
67 left,
68 right,
69 uchyph,
70 ..GlyphData::default()
71 }),
72 )
73 }
74
75 pub fn node_process_list(&mut self, first: NodeRef, _ctx: Context) -> NodeRef {
78 if first.is_null() {
79 return first;
80 }
81 self.fonts.sync_dense();
82 let head = self.nodes.new_temp();
83 self.nodes.link(head, first);
84 self.hyphenate_list(head);
85 self.ligature_list(head, true);
86 self.kern_list(head);
87 let first = self.nodes.next(head);
88 if !first.is_null() {
89 self.nodes.set_prev(first, NodeRef::NULL);
90 }
91 self.nodes.free(head);
92 first
93 }
94
95 fn hyphenate_list(&mut self, head: NodeRef) {
101 let ex = self.eqtb.int(ip::EXHYPHENCHAR);
102 let pen = self.eqtb.int(ip::EXHYPHENPENALTY);
103 if ex > 0 {
104 let ex = ex as u32;
105 let is_hyphen = |e: &Engine, n: NodeRef| e.nodes.glyph(n).is_some_and(|g| g.chr == ex);
106 let mut armed = true;
109 let mut prev = head;
110 let mut p = self.nodes.next(head);
111 while !p.is_null() {
112 if !is_hyphen(self, p) {
113 match self.nodes.id(p) {
114 id::GLUE => armed = true,
115 id::KERN => armed = false,
116 _ => {}
117 }
118 prev = p;
119 p = self.nodes.next(p);
120 continue;
121 }
122 let mut last = p;
124 let mut len = 1;
125 let mut q = self.nodes.next(p);
126 while !q.is_null() && is_hyphen(self, q) {
127 last = q;
128 len += 1;
129 q = self.nodes.next(q);
130 }
131 let followed = !q.is_null() && self.nodes.is_glyph(q);
132 let convert =
133 followed && (len == 1 || (armed && prev != head && self.has_hj_code(prev)));
134 if !convert {
135 prev = last;
136 p = q;
137 continue;
138 }
139 if len > 1 {
140 armed = false;
141 }
142 let before = if len == 1 {
144 prev
145 } else {
146 self.nodes.prev(last)
147 };
148 self.nodes.set_next(last, NodeRef::NULL);
149 let d = self.nodes.new_disc(2, pen);
150 if let Some(a) = self.nodes.attr(last).cloned() {
151 self.nodes.set_attr(d, Some(a));
152 }
153 let pre = self.nodes.copy_list(last);
154 self.nodes.set_prev(last, NodeRef::NULL);
155 self.nodes.set_disc_lists(d, (pre, NodeRef::NULL, last));
156 self.nodes.link(before, d);
157 self.nodes.link(d, q);
158 prev = d;
159 p = q;
160 }
161 }
162 if !self.languages.is_empty() {
163 self.pattern_hyphenate(head);
164 }
165 }
166
167 fn has_hj_code(&self, p: NodeRef) -> bool {
170 let Some(g) = self.nodes.glyph(p) else {
171 return false;
172 };
173 let lang = u32::from(g.lang);
174 let c = g.chr;
175 let code = match self.language(lang) {
176 Some(l) if l.has_hj_codes() => l.hj_code(c),
177 _ => self.eqtb.lc.get(c).max(0) as u32,
178 };
179 code != 0
180 }
181
182 fn pattern_hyphenate(&mut self, head: NodeRef) {
195 let hpen = self.eqtb.int(ip::HYPHENPENALTY);
196 let auto_ok = self.eqtb.int(ip::AUTOMATICHYPHENMODE) != 0;
197 let mut run: Vec<NodeRef> = Vec::new();
198 let mut word: Vec<NodeRef> = Vec::new();
199 let mut codes: Vec<u32> = Vec::new();
200 let mut pos: Vec<usize> = Vec::new();
201 let mut can_start = true;
202 let mut seen_glyph = false;
203 let mut p = self.nodes.next(head);
204 while !p.is_null() {
205 if self.nodes.is_glyph(p) && self.nodes.subtype(p) & glyph_sub::CHARACTER != 0 {
206 run.clear();
208 let mut q = p;
209 while !q.is_null()
210 && self.nodes.is_glyph(q)
211 && self.nodes.subtype(q) & glyph_sub::CHARACTER != 0
212 {
213 run.push(q);
214 q = self.nodes.next(q);
215 }
216 let end_ok = q.is_null()
217 || match self.nodes.id(q) {
218 id::DISC => auto_ok && self.nodes.subtype(q) == 2,
219 id::MATH | id::MARK => false,
220 _ => true,
221 };
222 let bounds = (can_start, end_ok);
223 self.hyphenate_run(&run, hpen, bounds, &mut word, &mut codes, &mut pos);
224 seen_glyph = true;
225 p = q;
226 continue;
227 }
228 match self.nodes.id(p) {
229 id::GLUE => can_start = true,
230 id::KERN | id::PENALTY | id::MARK | id::ADJUST => can_start &= !seen_glyph,
231 id::DISC if auto_ok && self.nodes.subtype(p) == 2 => can_start = true,
232 id::DISC => can_start &= !seen_glyph,
233 _ => {}
234 }
235 p = self.nodes.next(p);
236 }
237 }
238
239 fn hyphenate_run(
242 &mut self,
243 run: &[NodeRef],
244 hpen: i32,
245 bounds: (bool, bool),
246 word: &mut Vec<NodeRef>,
247 codes: &mut Vec<u32>,
248 pos: &mut Vec<usize>,
249 ) {
250 if !bounds.0 {
251 return;
252 }
253 let mut i = 0;
254 while i < run.len() {
255 let Some(g0) = self.nodes.glyph(run[i]).cloned() else {
257 i += 1;
258 continue;
259 };
260 let lang = u32::from(g0.lang);
261 word.clear();
262 codes.clear();
263 let ex = self.eqtb.int(ip::EXHYPHENCHAR);
267 let mut with_hyphen = false;
268 while i < run.len() {
269 let Some(g) = self.nodes.glyph(run[i]) else {
270 break;
271 };
272 if u32::from(g.lang) != lang {
273 break;
274 }
275 let c = g.chr;
276 let code = match self.language(lang) {
277 Some(l) if l.has_hj_codes() => l.hj_code(c),
278 _ => self.eqtb.lc.get(c).max(0) as u32,
279 };
280 if code == 0 {
281 if word.is_empty() {
282 with_hyphen = ex > 0 && c == ex as u32;
283 i += 1;
284 continue;
285 }
286 with_hyphen |= ex > 0 && c == ex as u32;
287 break;
288 }
289 with_hyphen |= ex > 0 && c == ex as u32;
290 word.push(run[i]);
291 codes.push(code);
292 i += 1;
293 }
294 if word.len() < 2 || with_hyphen {
295 continue;
296 }
297 if !bounds.1 && word.last() == run.last() {
298 continue;
299 }
300 let Some(first) = self.nodes.glyph(word[0]).cloned() else {
301 continue;
302 };
303 if first.font == 0 || self.font(first.font).hyphen_char < 0 {
304 continue;
305 }
306 if !first.uchyph && codes[0] != first.chr {
307 continue;
308 }
309 let Some(language) = self.language(lang) else {
310 continue;
311 };
312 pos.clear();
313 let _ =
314 language.hyphenate_into(codes, u32::from(first.left), u32::from(first.right), pos);
315 if pos.is_empty() {
316 continue;
317 }
318 let settings = language.settings;
319 pos.sort_unstable();
320 pos.dedup();
321 for &k in pos.iter().rev() {
322 if k == 0 || k >= word.len() {
323 continue;
324 }
325 let left = word[k - 1];
326 let right = word[k];
327 let f = self.nodes.glyph(left).map_or(0, |g| g.font);
328 let d = self.nodes.new_disc(3, hpen);
329 if let Some(a) = self.nodes.attr(left).cloned() {
330 self.nodes.set_attr(d, Some(a));
331 }
332 let mk = |e: &mut Engine, c: i32| {
333 if c > 0 {
334 let mut g = e.nodes.glyph(left).cloned().unwrap_or_default();
335 g.chr = c as u32;
336 g.font = f;
337 g.components = NodeRef::NULL;
338 let a = e.nodes.attr(left).cloned();
341 let n = e
342 .nodes
343 .alloc(id::GLYPH, glyph_sub::CHARACTER, NodeData::Glyph(g));
344 e.nodes.set_attr(n, a);
345 n
346 } else {
347 NodeRef::NULL
348 }
349 };
350 let pre = mk(self, settings.pre_hyphen_char);
351 let post = mk(self, settings.post_hyphen_char);
352 self.nodes.set_disc_lists(d, (pre, post, NodeRef::NULL));
353 self.nodes.link(left, d);
354 self.nodes.link(d, right);
355 }
356 }
357 }
358
359 #[inline]
363 fn glyph_of_font(&self, p: NodeRef, f: u32) -> Option<u32> {
364 if p.is_null() {
365 return None;
366 }
367 match self.nodes.data(p) {
368 NodeData::Glyph(g) if g.font == f && self.nodes.subtype(p) & glyph_sub::GHOST == 0 => {
369 Some(g.chr)
370 }
371 _ => None,
372 }
373 }
374
375 #[inline]
377 fn lig_step(&self, f: u32, l: u32, r: u32) -> Option<(u8, u32)> {
378 match self.lig_kern_step(f, l, r) {
379 Some(LigOp::Lig { op, chr }) => Some((op, chr)),
380 _ => None,
381 }
382 }
383
384 fn take_components(&mut self, p: NodeRef) -> NodeRef {
387 let is_lig = self.nodes.subtype(p) & glyph_sub::LIGATURE != 0;
388 if is_lig {
389 let c = self
390 .nodes
391 .glyph_mut(p)
392 .map(|g| std::mem::take(&mut g.components));
393 let c = c.unwrap_or(NodeRef::NULL);
394 self.nodes.free(p);
395 if c.is_null() {
396 return NodeRef::NULL;
397 }
398 c
399 } else {
400 self.nodes.set_next(p, NodeRef::NULL);
401 self.nodes.set_prev(p, NodeRef::NULL);
402 let s = self.nodes.subtype(p) & !glyph_sub::CHARACTER;
403 self.nodes.set_subtype(p, s);
404 p
405 }
406 }
407
408 fn new_ligature(&mut self, model: NodeRef, c: u32, comps: NodeRef) -> NodeRef {
411 let mut g = self.nodes.glyph(model).cloned().unwrap_or_default();
412 g.chr = c;
413 g.components = comps;
414 let a = self.nodes.attr(model).cloned();
415 let n = self
416 .nodes
417 .alloc(id::GLYPH, glyph_sub::LIGATURE, NodeData::Glyph(g));
418 self.nodes.set_attr(n, a);
419 n
420 }
421
422 fn concat(&mut self, a: NodeRef, b: NodeRef) -> NodeRef {
424 if a.is_null() {
425 return b;
426 }
427 if !b.is_null() {
428 let t = self.nodes.tail_of(a);
429 self.nodes.link(t, b);
430 }
431 a
432 }
433
434 fn replace_node(&mut self, prev: NodeRef, old_next: NodeRef, new: NodeRef) {
436 self.nodes.link(prev, new);
437 self.nodes.link(new, old_next);
438 if old_next.is_null() {
439 self.nodes.set_next(new, NodeRef::NULL);
440 }
441 }
442
443 fn ligature_list(&mut self, head: NodeRef, main: bool) {
446 let mut prev = head;
447 let mut p = self.nodes.next(head);
448 while !p.is_null() {
449 match self.nodes.id(p) {
450 id::BOUNDARY if main => {
451 let n = self.nodes.next(p);
452 self.nodes.set_next(prev, n);
453 if !n.is_null() {
454 self.nodes.set_prev(n, prev);
455 }
456 self.nodes.free(p);
457 p = n;
458 }
459 id::GLYPH => {
460 let (last_prev, last) = self.ligature_run(prev, p);
461 let n = self.nodes.next(last);
464 if main
465 && (n.is_null()
466 || !matches!(self.nodes.id(n), id::GLYPH | id::DISC | id::BOUNDARY))
467 {
468 self.right_boundary_kern(last);
469 }
470 if !n.is_null() && self.nodes.id(n) == id::DISC {
471 let (np, nd) = self.lig_disc(last_prev, last, n);
472 prev = np;
473 p = nd;
474 } else {
475 prev = last;
476 p = n;
477 }
478 }
479 id::DISC => {
480 self.lig_disc_lists(p);
481 prev = p;
482 p = self.nodes.next(p);
483 }
484 _ => {
485 prev = p;
486 p = self.nodes.next(p);
487 }
488 }
489 }
490 }
491
492 fn right_boundary_kern(&mut self, p: NodeRef) {
498 let Some((f, l)) = self.nodes.glyph(p).map(|g| (g.font, g.chr)) else {
499 return;
500 };
501 let Some(b) = self.font(f).right_boundary else {
502 return;
503 };
504 if let Some(k) = self.kern_between(f, l, b) {
505 let kn = self.font_kern(k, p);
506 let n = self.nodes.next(p);
507 self.nodes.link(p, kn);
508 self.nodes.link(kn, n);
509 }
510 }
511
512 fn lig_disc_lists(&mut self, d: NodeRef) {
514 let (pre, post, rep) = self.nodes.disc_lists(d);
515 let pre = self.ligature_sublist(pre);
516 let post = self.ligature_sublist(post);
517 let rep = self.ligature_sublist(rep);
518 self.nodes.set_disc_lists(d, (pre, post, rep));
519 }
520
521 fn ligature_sublist(&mut self, l: NodeRef) -> NodeRef {
523 if l.is_null() {
524 return l;
525 }
526 let h = self.nodes.new_temp();
527 self.nodes.link(h, l);
528 self.ligature_list(h, false);
529 let r = self.nodes.next(h);
530 if !r.is_null() {
531 self.nodes.set_prev(r, NodeRef::NULL);
532 }
533 self.nodes.free(h);
534 r
535 }
536
537 fn lig_disc(&mut self, before: NodeRef, last: NodeRef, d: NodeRef) -> (NodeRef, NodeRef) {
542 let f = self.nodes.glyph(last).map_or(0, |g| g.font);
543 if self.font(f).lig_kern.is_empty() {
544 self.lig_disc_lists(d);
545 return (d, self.nodes.next(d));
546 }
547 let lc = self.nodes.glyph(last).map_or(0, |g| g.chr);
548 let (pre, post, rep) = self.nodes.disc_lists(d);
549 let after = self.nodes.next(d);
550 let crosses =
551 |e: &Engine, l: NodeRef| e.glyph_of_font(l, f).and_then(|c| e.lig_step(f, lc, c));
552 let left = crosses(self, pre).is_some()
553 || (!rep.is_null() && crosses(self, rep).is_some())
554 || (rep.is_null() && crosses(self, after).is_some());
555 let (mut pre, mut post, mut rep) = (pre, post, rep);
556 if left {
557 self.nodes.link(before, d);
559 self.nodes.set_next(last, NodeRef::NULL);
560 self.nodes.set_prev(last, NodeRef::NULL);
561 let copy = self.nodes.copy_node(last);
562 pre = self.concat(copy, pre);
563 rep = self.concat(last, rep);
564 }
565 loop {
568 let n = self.nodes.next(d);
569 let Some(nc) = self.glyph_of_font(n, f) else {
570 break;
571 };
572 let ends = |e: &Engine, l: NodeRef| {
573 if l.is_null() {
574 return false;
575 }
576 let t = e.nodes.tail_of(l);
577 e.glyph_of_font(t, f)
578 .is_some_and(|c| e.lig_step(f, c, nc).is_some())
579 };
580 if !(ends(self, post) || ends(self, rep)) {
581 break;
582 }
583 let nn = self.nodes.next(n);
584 self.nodes.link(d, nn);
585 if nn.is_null() {
586 self.nodes.set_next(d, NodeRef::NULL);
587 }
588 self.nodes.set_next(n, NodeRef::NULL);
589 self.nodes.set_prev(n, NodeRef::NULL);
590 let copy = self.nodes.copy_node(n);
591 post = self.concat(post, copy);
592 rep = self.concat(rep, n);
593 }
594 self.nodes.set_disc_lists(d, (pre, post, rep));
595 self.lig_disc_lists(d);
596 (d, self.nodes.next(d))
597 }
598
599 fn ligature_run(&mut self, prev: NodeRef, p: NodeRef) -> (NodeRef, NodeRef) {
603 let f = self.nodes.glyph(p).map_or(0, |g| g.font);
604 if self.font(f).lig_kern.is_empty() {
605 let (mut qp, mut q) = (prev, p);
607 loop {
608 let n = self.nodes.next(q);
609 if self.glyph_of_font(n, f).is_none() {
610 return (qp, q);
611 }
612 qp = q;
613 q = n;
614 }
615 }
616 let mut cur_prev = prev;
617 let mut cur = p;
618 let mut guard = 0u32;
619 loop {
620 let nxt = self.nodes.next(cur);
621 let (Some(l), Some(r)) = (self.glyph_of_font(cur, f), self.glyph_of_font(nxt, f))
622 else {
623 return (cur_prev, cur);
624 };
625 guard += 1;
626 if guard > 100_000 {
627 return (cur_prev, cur);
629 }
630 let Some((op, c)) = self.lig_step(f, l, r) else {
631 cur_prev = cur;
632 cur = nxt;
633 continue;
634 };
635 let after = self.nodes.next(nxt);
636 match op {
637 0 => {
638 let a = self.take_components(cur);
640 let b = self.take_components(nxt);
641 let comps = self.concat(a, b);
642 let model = if comps.is_null() { cur } else { comps };
643 let lig = self.new_ligature(model, c, comps);
644 self.replace_node(cur_prev, after, lig);
645 cur = lig;
646 }
647 1 | 5 => {
648 let a = self.take_components(cur);
650 let model = if a.is_null() { nxt } else { a };
651 let lig = self.new_ligature(model, c, a);
652 self.replace_node(cur_prev, nxt, lig);
653 if op == 5 {
654 cur_prev = lig;
655 cur = nxt;
656 } else {
657 cur = lig;
658 }
659 }
660 2 | 6 => {
661 let b = self.take_components(nxt);
663 let model = if b.is_null() { cur } else { b };
664 let lig = self.new_ligature(model, c, b);
665 self.replace_node(cur, after, lig);
666 if op == 6 {
667 cur_prev = cur;
668 cur = lig;
669 }
670 }
671 _ => {
672 let lig = self.new_ligature(cur, c, NodeRef::NULL);
674 self.nodes.set_subtype(lig, 0);
675 self.replace_node(cur, nxt, lig);
676 match op {
677 7 => {
678 cur_prev = cur;
679 cur = lig;
680 }
681 11 => {
682 cur_prev = lig;
683 cur = nxt;
684 }
685 _ => {}
686 }
687 }
688 }
689 }
690 }
691
692 #[inline]
696 fn kern_between(&self, f: u32, l: u32, r: u32) -> Option<i32> {
697 match self.lig_kern_step(f, l, r) {
698 Some(LigOp::Kern(k)) => Some(k),
699 _ => None,
700 }
701 }
702
703 fn font_kern(&mut self, k: i32, model: NodeRef) -> NodeRef {
705 let n = self.nodes.new_kern(k, kern_sub::FONT);
706 let a = self.nodes.attr(model).cloned();
707 self.nodes.set_attr(n, a);
708 n
709 }
710
711 fn kern_list(&mut self, head: NodeRef) {
714 let mut p = self.nodes.next(head);
715 while !p.is_null() {
716 match self.nodes.id(p) {
717 id::GLYPH => {
718 let s = self.nodes.subtype(p) & !glyph_sub::CHARACTER;
719 self.nodes.set_subtype(p, s);
720 let n = self.nodes.next(p);
721 if n.is_null() {
722 break;
723 }
724 let (f, l) = match self.nodes.glyph(p) {
725 Some(g) => (g.font, g.chr),
726 None => break,
727 };
728 if self.nodes.id(n) == id::GLYPH {
729 if let Some(r) = self.glyph_of_font(n, f)
730 && let Some(k) = self.kern_between(f, l, r)
731 {
732 let kn = self.font_kern(k, p);
733 self.nodes.link(p, kn);
734 self.nodes.link(kn, n);
735 }
736 p = n;
737 } else if self.nodes.id(n) == id::DISC {
738 self.kern_disc(p, n);
739 p = self.nodes.next(n);
740 } else {
741 p = n;
742 }
743 }
744 id::DISC => {
745 self.kern_disc(NodeRef::NULL, p);
746 p = self.nodes.next(p);
747 }
748 _ => p = self.nodes.next(p),
749 }
750 }
751 }
752
753 fn kern_disc(&mut self, before: NodeRef, d: NodeRef) {
756 let (mut pre, mut post, mut rep) = self.nodes.disc_lists(d);
757 pre = self.kern_sublist(pre);
758 post = self.kern_sublist(post);
759 let rep_was_empty = rep.is_null();
760 rep = self.kern_sublist(rep);
761 let after = self.nodes.next(d);
762 let bg = if before.is_null() {
763 None
764 } else {
765 self.nodes.glyph(before).map(|g| (g.font, g.chr))
766 };
767 let ag = if after.is_null() || self.nodes.id(after) != id::GLYPH {
768 None
769 } else {
770 self.nodes.glyph(after).map(|g| (g.font, g.chr))
771 };
772 if let Some((f, l)) = bg {
773 if let Some(r) = self.glyph_of_font(pre, f)
774 && let Some(k) = self.kern_between(f, l, r)
775 {
776 let kn = self.font_kern(k, before);
777 self.nodes.link(kn, pre);
778 pre = kn;
779 }
780 if !rep_was_empty {
781 if let Some(r) = self.glyph_of_font(rep, f)
782 && let Some(k) = self.kern_between(f, l, r)
783 {
784 let kn = self.font_kern(k, before);
785 self.nodes.link(kn, rep);
786 rep = kn;
787 }
788 } else if let Some((af, ac)) = ag
789 && af == f
790 && let Some(k) = self.kern_between(f, l, ac)
791 {
792 rep = self.font_kern(k, before);
793 }
794 }
795 if let Some((f, r)) = ag {
796 if !post.is_null() {
797 let t = self.nodes.tail_of(post);
798 if let Some(l) = self.glyph_of_font(t, f)
799 && let Some(k) = self.kern_between(f, l, r)
800 {
801 let kn = self.font_kern(k, after);
802 self.nodes.link(t, kn);
803 }
804 }
805 if !rep_was_empty {
806 let t = self.nodes.tail_of(rep);
807 if let Some(l) = self.glyph_of_font(t, f)
808 && let Some(k) = self.kern_between(f, l, r)
809 {
810 let kn = self.font_kern(k, after);
811 self.nodes.link(t, kn);
812 }
813 }
814 }
815 self.nodes.set_disc_lists(d, (pre, post, rep));
816 }
817
818 fn kern_sublist(&mut self, l: NodeRef) -> NodeRef {
820 if l.is_null() {
821 return l;
822 }
823 let h = self.nodes.new_temp();
824 self.nodes.link(h, l);
825 self.kern_list(h);
826 let r = self.nodes.next(h);
827 if !r.is_null() {
828 self.nodes.set_prev(r, NodeRef::NULL);
829 }
830 self.nodes.free(h);
831 r
832 }
833}