swash/shape/
buffer.rs

1use super::cluster::{Glyph, GlyphInfo};
2use super::feature::*;
3use crate::text::{
4    cluster::{Char, CharCluster, ClusterInfo, ShapeClass, SourceRange, MAX_CLUSTER_SIZE},
5    JoiningType,
6};
7
8use alloc::vec::Vec;
9use core::ops::Range;
10
11// Glyph flags.
12pub const SUBSTITUTED: u16 = 1;
13pub const LIGATED: u16 = 2;
14pub const COMPONENT: u16 = 4;
15pub const MARK_ATTACH: u16 = 8;
16pub const CURSIVE_ATTACH: u16 = 16;
17pub const IGNORABLE: u16 = 64;
18
19/// Per glyph shaping data.
20#[derive(Copy, Clone, Default, Debug)]
21pub struct GlyphData {
22    pub id: u16,
23    pub flags: u16,
24    pub class: u8,
25    pub char_class: ShapeClass,
26    pub mark_type: u8,
27    pub joining_type: u8,
28    pub mask: u8,
29    pub skip: bool,
30    pub component: u8,
31    pub cluster: u32,
32    pub data: u32,
33}
34
35impl GlyphData {
36    pub fn is_component(&self) -> bool {
37        self.flags & COMPONENT != 0
38    }
39}
40
41/// Per glyph shaping position data.
42#[derive(Copy, Clone, Default, Debug)]
43pub struct PositionData {
44    pub base: u8,
45    pub flags: u16,
46    pub x: f32,
47    pub y: f32,
48    pub advance: f32,
49}
50
51impl Glyph {
52    pub(super) fn new(g: &GlyphData, p: &PositionData) -> Self {
53        Self {
54            id: g.id,
55            info: GlyphInfo(p.flags),
56            x: p.x,
57            y: p.y,
58            advance: p.advance,
59            data: g.data,
60        }
61    }
62}
63
64#[derive(Clone, Default)]
65pub struct Buffer {
66    pub glyphs: Vec<GlyphData>,
67    pub positions: Vec<PositionData>,
68    pub infos: Vec<(ClusterInfo, bool, u32)>,
69    pub ranges: Vec<SourceRange>,
70    pub shaped_glyphs: Vec<Glyph>,
71    pub is_rtl: bool,
72    pub dotted_circle: Option<u16>,
73    pub has_cursive: bool,
74    pub has_marks: bool,
75    pub reversed: bool,
76    pub next_cluster: u32,
77    pub skip_state: SkipState,
78    pub sub_args: Vec<u16>,
79    pub pos_args: Vec<u16>,
80}
81
82#[derive(Copy, Clone, PartialEq, Eq, Default)]
83pub struct SkipState {
84    pub flags: u8,
85    pub mask: u8,
86    pub mark_check: u8,
87    pub mark_class: u8,
88    pub mark_set: u32,
89}
90
91impl Buffer {
92    pub fn new() -> Self {
93        Self::default()
94    }
95
96    pub fn len(&self) -> usize {
97        self.glyphs.len()
98    }
99
100    pub fn push(&mut self, cluster: &CharCluster) -> Range<usize> {
101        let start = self.glyphs.len();
102        let chars = cluster.mapped_chars();
103        if cluster.info().is_broken() {
104            if let Some(id) = self.dotted_circle {
105                let first = &chars[0];
106                self.push_char(&Char {
107                    ch: '\u{25cc}',
108                    shape_class: ShapeClass::Base,
109                    joining_type: JoiningType::U,
110                    ignorable: false,
111                    contributes_to_shaping: true,
112                    glyph_id: id,
113                    offset: first.offset,
114                    data: first.data,
115                });
116            }
117        }
118        for ch in chars {
119            self.push_char(ch);
120        }
121        self.next_cluster += 1;
122        self.push_cluster(cluster);
123        start..self.glyphs.len()
124    }
125
126    pub fn push_order(&mut self, cluster: &CharCluster, order: &[usize]) -> Range<usize> {
127        let start = self.glyphs.len();
128        let chars = cluster.mapped_chars();
129        if cluster.info().is_broken() {
130            if let Some(id) = self.dotted_circle {
131                let first = &chars[order[0]];
132                self.push_char(&Char {
133                    ch: '\u{25cc}',
134                    shape_class: ShapeClass::Base,
135                    joining_type: JoiningType::U,
136                    ignorable: false,
137                    contributes_to_shaping: true,
138                    glyph_id: id,
139                    offset: first.offset,
140                    data: first.data,
141                });
142            }
143        }
144        for ch in order[..chars.len()].iter().map(|i| &chars[*i]) {
145            self.push_char(ch);
146        }
147        self.next_cluster += 1;
148        self.push_cluster(cluster);
149        start..self.glyphs.len()
150    }
151
152    pub fn _push_hangul(&mut self, cluster: &CharCluster) -> Range<usize> {
153        let start = self.glyphs.len();
154        let chars = cluster.mapped_chars();
155        if cluster.info().is_broken() {
156            if let Some(id) = self.dotted_circle {
157                let first = &chars[0];
158                self.push_char(&Char {
159                    ch: '\u{25cc}',
160                    shape_class: ShapeClass::Base,
161                    joining_type: JoiningType::U,
162                    ignorable: false,
163                    contributes_to_shaping: true,
164                    glyph_id: id,
165                    offset: first.offset,
166                    data: first.data,
167                });
168            }
169        }
170        for ch in chars {
171            self._push_hangul_char(ch);
172        }
173        self.next_cluster += 1;
174        self.push_cluster(cluster);
175        start..self.glyphs.len()
176    }
177
178    #[inline(always)]
179    fn push_char(&mut self, ch: &Char) {
180        let cluster = self.next_cluster;
181        self.glyphs.push(GlyphData {
182            id: ch.glyph_id,
183            flags: (ch.ignorable as u16) << 6,
184            class: 0,
185            char_class: ch.shape_class,
186            joining_type: ch.joining_type as u8,
187            mark_type: 0,
188            mask: 0,
189            skip: false,
190            component: !0,
191            cluster,
192            data: ch.data,
193        });
194    }
195
196    fn _push_hangul_char(&mut self, ch: &Char) {
197        let cluster = self.next_cluster;
198        let c = ch.ch as u32;
199        let mask = if (0x1100..=0x115F).contains(&c) || (0xA960..=0xA97C).contains(&c) {
200            1
201        } else if (0x1160..=0x11A7).contains(&c) || (0xD7B0..=0xD7C6).contains(&c) {
202            2
203        } else if (0x11A8..=0x11FF).contains(&c) || (0xD7CB..=0xD7FB).contains(&c) {
204            4
205        } else {
206            1 | 2 | 4
207        };
208        self.glyphs.push(GlyphData {
209            id: ch.glyph_id,
210            flags: (ch.ignorable as u16) << 6,
211            class: 0,
212            char_class: ch.shape_class,
213            joining_type: ch.joining_type as u8,
214            mark_type: 0,
215            mask,
216            skip: false,
217            component: !0,
218            cluster,
219            data: ch.data,
220        });
221    }
222
223    fn push_cluster(&mut self, cluster: &CharCluster) {
224        self.infos
225            .push((cluster.info(), false, cluster.user_data()));
226        self.ranges.push(cluster.range());
227    }
228
229    pub fn clear(&mut self) {
230        self.glyphs.clear();
231        self.positions.clear();
232        self.infos.clear();
233        self.ranges.clear();
234        self.is_rtl = false;
235        self.reversed = false;
236        self.has_cursive = false;
237        self.has_marks = false;
238        self.dotted_circle = None;
239        self.next_cluster = 0;
240        self.skip_state = SkipState::default();
241    }
242
243    pub fn ensure_order(&mut self, reversed: bool) {
244        if reversed != self.reversed {
245            self.glyphs.reverse();
246            if !self.positions.is_empty() {
247                self.positions.reverse();
248            }
249            self.reversed = reversed;
250        }
251    }
252
253    pub fn clear_flags(&mut self, flags: u16, range: Option<Range<usize>>) {
254        if let Some(range) = range {
255            for g in &mut self.glyphs[range] {
256                g.flags &= !flags;
257            }
258        } else {
259            for g in &mut self.glyphs {
260                g.flags &= !flags;
261            }
262        }
263    }
264
265    pub fn setup_positions(&mut self, was_morx: bool) {
266        if was_morx {
267            self.glyphs
268                .retain(|g| g.flags & COMPONENT == 0 && g.id != 0xFFFF);
269        } else {
270            self.glyphs.retain(|g| g.flags & COMPONENT == 0);
271        }
272        self.positions.clear();
273        self.positions
274            .resize(self.glyphs.len(), PositionData::default());
275    }
276
277    pub fn substitute(&mut self, index: usize, id: u16) {
278        let g = &mut self.glyphs[index];
279        // if TRACE {
280        //     println!("!subst[{}] {} -> {}", index, g.id, id);
281        // }
282        g.id = id;
283        g.flags |= SUBSTITUTED;
284    }
285
286    pub fn substitute_ligature(&mut self, index: usize, id: u16, components: &[usize]) {
287        // if TRACE {
288        //     print!("!subst[{}] {}", index, self.glyphs[index].id);
289        //     for c in components {
290        //         print!(" {}", self.glyphs[*c].id)
291        //     }
292        //     println!(" -> {}", id);
293        // }
294        if components.is_empty() {
295            return;
296        }
297        let g = &mut self.glyphs[index];
298        g.id = id;
299        g.flags |= SUBSTITUTED | LIGATED;
300        let cluster = g.cluster;
301        let mut last_index = index;
302        for (i, &index) in components.iter().enumerate() {
303            let g = &mut self.glyphs[index];
304            self.infos[g.cluster as usize].1 = true;
305            g.id = 0xFFFF;
306            g.flags |= COMPONENT;
307            g.class = 5;
308            g.cluster = cluster;
309            g.skip = true;
310            if (index - last_index) > 1 {
311                let component = i as u8;
312                for g in &mut self.glyphs[last_index + 1..index] {
313                    if g.mark_type != 0 || g.class == 3 {
314                        g.component = component;
315                        g.cluster = cluster;
316                    }
317                }
318            }
319            last_index = index;
320        }
321        if (last_index + 1) < self.glyphs.len() {
322            let last_component = components.len() as u8;
323            for g in &mut self.glyphs[last_index + 1..] {
324                if g.mark_type != 0 || g.class == 3 {
325                    g.component = last_component;
326                    g.cluster = cluster;
327                } else {
328                    break;
329                }
330            }
331        }
332    }
333
334    pub fn substitute_multiple(&mut self, index: usize, ids: &[u16]) {
335        let count = ids.len();
336        if count == 0 {
337            self.glyphs.remove(index);
338            return;
339        } else if count == 1 {
340            self.substitute(index, ids[0]);
341            return;
342        }
343        // if TRACE {
344        //     println!("!subst[{}] {} -> {:?}", index, self.glyphs[index].id, ids);
345        // }
346        let g = self.glyphs[index];
347        self.glyphs
348            .splice(index..index + 1, SubstIter { ids, g, cur: 0 });
349    }
350
351    pub fn multiply(&mut self, index: usize, count: usize) {
352        let g = self
353            .glyphs
354            .get(index)
355            .copied()
356            .unwrap_or_else(GlyphData::default);
357        self.glyphs.splice(index..index, (0..count).map(|_| g));
358    }
359
360    pub fn position(&mut self, index: usize, x: f32, y: f32, xadvance: f32, _yadvance: f32) {
361        let p = &mut self.positions[index];
362        p.x += x;
363        p.y += y;
364        p.advance += xadvance;
365    }
366
367    pub fn position_cursive(&mut self, index: usize, next: usize, x: f32, y: f32) {
368        let p = &mut self.positions[index];
369        self.has_cursive = true;
370        p.flags = CURSIVE_ATTACH;
371        if true {
372            //self.dir.is_horizontal() {
373            p.y = y;
374        //p.advance -= x;
375        } else {
376            p.x = x;
377        }
378        p.base = (next - index) as u8;
379    }
380
381    pub fn position_mark(&mut self, index: usize, base: usize, dx: f32, dy: f32) {
382        let p = &mut self.positions[index];
383        self.has_marks = true;
384        p.flags = MARK_ATTACH;
385        p.base = (index - base) as u8;
386        p.x = dx;
387        p.y = dy;
388    }
389
390    pub fn set_join_masks(&mut self) {
391        let mut prev: Option<usize> = None;
392        let mut state = 0;
393        let glyphs = &mut self.glyphs;
394        let len = glyphs.len();
395        // Transparent joining type.
396        const JOIN_T: u8 = 6;
397        for i in 0..len {
398            let ty = glyphs[i].joining_type;
399            if ty == JOIN_T {
400                continue;
401            }
402            let entry = JOIN_STATES[state][ty as usize];
403            if let Some(j) = prev {
404                if entry.0 != NONE_MASK {
405                    glyphs[j].mask = entry.0;
406                }
407            }
408            glyphs[i].mask = entry.1;
409            prev = Some(i);
410            state = entry.2 as usize;
411        }
412    }
413}
414
415struct SubstIter<'a> {
416    ids: &'a [u16],
417    g: GlyphData,
418    cur: usize,
419}
420
421impl<'a> Iterator for SubstIter<'a> {
422    type Item = GlyphData;
423
424    fn size_hint(&self) -> (usize, Option<usize>) {
425        let remaining = self.ids.len() - self.cur;
426        (remaining, Some(remaining))
427    }
428
429    fn next(&mut self) -> Option<Self::Item> {
430        if self.cur >= self.ids.len() {
431            return None;
432        }
433        let g = GlyphData {
434            id: self.ids[self.cur],
435            flags: SUBSTITUTED,
436            ..self.g
437        };
438        self.cur += 1;
439        Some(g)
440    }
441}
442
443pub fn reorder_myanmar(chars: &[Char], order: &mut Vec<usize>) {
444    use ShapeClass::*;
445    let mut ignored = [false; MAX_CLUSTER_SIZE];
446    let mut base = None;
447    let mut kinzi: Option<Range<usize>> = None;
448    let mut medial_ra = None;
449    let mut vpre: Option<Range<usize>> = None;
450    let mut vblw: Option<usize> = None;
451    let mut anus: Option<Range<usize>> = None;
452    let mut i = 0;
453    let mut last_vblw = false;
454    let len = chars.len();
455    if len == 0 {
456        return;
457    }
458    if order.len() < len {
459        order.resize(chars.len(), 0);
460    }
461    if chars[0].shape_class == Kinzi {
462        kinzi = Some(0..3);
463        ignored[0] = true;
464        ignored[1] = true;
465        ignored[2] = true;
466        i = 3;
467    }
468    while i < len {
469        let ch = chars[i];
470        let k = ch.shape_class;
471        if last_vblw && k == Anusvara {
472            anus = match anus {
473                Some(r) => Some(r.start..i - r.start + 1),
474                None => Some(i..i + 1),
475            };
476            ignored[i] = true;
477            i += 1;
478            continue;
479        }
480        last_vblw = false;
481        if k == VBlw {
482            if vblw.is_none() {
483                vblw = Some(i);
484            }
485            last_vblw = true;
486        }
487        if k == Base && base.is_none() {
488            base = Some(i);
489            ignored[i] = true;
490        } else if k == MedialRa {
491            medial_ra = Some(i);
492            ignored[i] = true;
493        } else if k == VPre {
494            vpre = match vpre {
495                Some(r) => Some(r.start..i - r.start + 1),
496                None => Some(i..i + 1),
497            };
498            ignored[i] = true;
499        }
500        i += 1;
501    }
502    i = 0;
503    if let Some(r) = vpre {
504        for j in r {
505            order[i] = j;
506            i += 1;
507        }
508    }
509    if let Some(j) = medial_ra {
510        order[i] = j;
511        i += 1;
512    }
513    if let Some(j) = base {
514        order[i] = j;
515        i += 1;
516    }
517    if let Some(r) = kinzi {
518        for j in r {
519            order[i] = j;
520            i += 1;
521        }
522    }
523    let mut j = 0;
524    while j < len {
525        if ignored[j] {
526            j += 1;
527            continue;
528        }
529        if Some(j) == vblw && anus.is_some() {
530            for k in anus.take().unwrap() {
531                order[i] = k;
532                i += 1;
533            }
534        }
535        order[i] = j;
536        i += 1;
537        j += 1;
538    }
539}
540
541#[allow(clippy::needless_range_loop)]
542pub fn reorder_complex(glyphs: &mut [GlyphData], buf: &mut Vec<GlyphData>, order: &mut Vec<usize>) {
543    use ShapeClass::*;
544    let mut first_base = None;
545    let mut last_base = None;
546    let mut last_halant = None;
547    let mut reph = None;
548    let mut pref = None;
549    let mut vpre: Option<Range<usize>> = None;
550    let mut vmpre: Option<Range<usize>> = None;
551    let mut ignored = [false; 64];
552    let len = glyphs.len();
553    if buf.len() < glyphs.len() {
554        buf.resize(len, GlyphData::default());
555    }
556    let buf = &mut buf[..len];
557    if order.len() < len {
558        order.resize(len, 0);
559    }
560    let order = &mut order[..len];
561    for (i, g) in glyphs.iter().enumerate() {
562        if g.is_component() {
563            continue;
564        }
565        match g.char_class {
566            Base => {
567                if first_base.is_none() {
568                    first_base = Some(i);
569                    ignored[i] = true;
570                }
571                if last_halant.is_none() {
572                    last_base = Some(i);
573                }
574            }
575            Halant => {
576                last_halant = Some(i);
577            }
578            Reph => {
579                if reph.is_none() {
580                    reph = Some(i);
581                    ignored[i] = true;
582                }
583            }
584            Pref => {
585                if pref.is_none() {
586                    pref = Some(i);
587                    ignored[i] = true;
588                }
589            }
590            VPre => {
591                vpre = match vpre {
592                    Some(r) => Some(r.start..i - r.start + 1),
593                    None => Some(i..i + 1),
594                };
595                ignored[i] = true;
596            }
597            VMPre => {
598                vmpre = match vmpre {
599                    Some(r) => Some(r.start..i - r.start + 1),
600                    None => Some(i..i + 1),
601                };
602                ignored[i] = true;
603            }
604            _ => {}
605        }
606    }
607    let mut j = 0;
608    // No explicit virama; insert vmpre, vpre, pref
609    if last_halant.is_none() {
610        if let Some(r) = vmpre.clone() {
611            for i in r {
612                order[j] = i;
613                j += 1;
614            }
615        }
616        if let Some(r) = vpre.clone() {
617            for i in r {
618                order[j] = i;
619                j += 1;
620            }
621        }
622        if let Some(i) = pref {
623            order[j] = i;
624            j += 1;
625        }
626    }
627    // Insert the base...
628    if let Some(i) = first_base {
629        order[j] = i;
630        j += 1;
631    }
632    if last_base.is_none() {
633        // ... and the reph
634        if let Some(i) = reph {
635            order[j] = i;
636            j += 1;
637        }
638    }
639    // Now the rest
640    let len = glyphs.len();
641    for i in 0..len {
642        if ignored[i] {
643            continue;
644        }
645        // println!(" -> i = {}, j = {}", i, j);
646        // println!("order: {:?}", order);
647        // println!("ignored: {:?}", &ignored[0..order.len()]);
648        order[j] = i;
649        j += 1;
650        // Insert reph after final base
651        if Some(i) == last_base {
652            if let Some(i) = reph {
653                order[j] = i;
654                j += 1;
655            }
656        }
657        // Move vmpre, vpre and pref after the final virama
658        if Some(i) == last_halant {
659            if let Some(r) = vmpre.clone() {
660                for i in r {
661                    order[j] = i;
662                    j += 1;
663                }
664            }
665            if let Some(r) = vpre.clone() {
666                for i in r {
667                    order[j] = i;
668                    j += 1;
669                }
670            }
671            if let Some(i) = pref {
672                order[j] = i;
673                j += 1;
674            }
675        }
676    }
677    // Reorder glyphs
678    buf.copy_from_slice(glyphs);
679    for (i, j) in order.iter().enumerate() {
680        glyphs[i] = buf[*j];
681    }
682    // println!("order: {:?}", order);
683    // let new = glyphs
684    //     .iter()
685    //     .map(|g| (g.class, char_kind(g.subclass)))
686    //     .collect::<Vec<_>>();
687    // println!("new: {:?}", &new[..]);
688}
689
690// Matches the Arabic joining table from Harfbuzz.
691#[rustfmt::skip]
692const JOIN_STATES: [[(u8, u8, u8); 6]; 7] = [
693    //   U,                            L,                       R,                        D,                    ALAPH,                 DALATH_RISH
694    // State 0: prev was U, not willing to join.
695    [ (NONE_MASK,NONE_MASK,0), (NONE_MASK,ISOL_MASK,2), (NONE_MASK,ISOL_MASK,1), (NONE_MASK,ISOL_MASK,2), (NONE_MASK,ISOL_MASK,1), (NONE_MASK,ISOL_MASK,6), ],
696    // State 1: prev was R or ISOL_MASK/ALAPH, not willing to join.
697    [ (NONE_MASK,NONE_MASK,0), (NONE_MASK,ISOL_MASK,2), (NONE_MASK,ISOL_MASK,1), (NONE_MASK,ISOL_MASK,2), (NONE_MASK,FIN2_MASK,5), (NONE_MASK,ISOL_MASK,6), ],
698    // State 2: prev was D/L in ISOL_MASK form, willing to join.
699    [ (NONE_MASK,NONE_MASK,0), (NONE_MASK,ISOL_MASK,2), (INIT_MASK,FINA_MASK,1), (INIT_MASK,FINA_MASK,3), (INIT_MASK,FINA_MASK,4), (INIT_MASK,FINA_MASK,6), ],
700    // State 3: prev was D in FINA_MASK form, willing to join. */
701    [ (NONE_MASK,NONE_MASK,0), (NONE_MASK,ISOL_MASK,2), (MEDI_MASK,FINA_MASK,1), (MEDI_MASK,FINA_MASK,3), (MEDI_MASK,FINA_MASK,4), (MEDI_MASK,FINA_MASK,6), ],
702    // State 4: prev was FINA_MASK ALAPH, not willing to join. */
703    [ (NONE_MASK,NONE_MASK,0), (NONE_MASK,ISOL_MASK,2), (MED2_MASK,ISOL_MASK,1), (MED2_MASK,ISOL_MASK,2), (MED2_MASK,FIN2_MASK,5), (MED2_MASK,ISOL_MASK,6), ],
704    // State 5: prev was FIN2_MASK/FIN3_MASK ALAPH, not willing to join. */
705    [ (NONE_MASK,NONE_MASK,0), (NONE_MASK,ISOL_MASK,2), (ISOL_MASK,ISOL_MASK,1), (ISOL_MASK,ISOL_MASK,2), (ISOL_MASK,FIN2_MASK,5), (ISOL_MASK,ISOL_MASK,6), ],
706    // State 6: prev was DALATH/RISH, not willing to join. */
707    [ (NONE_MASK,NONE_MASK,0), (NONE_MASK,ISOL_MASK,2), (NONE_MASK,ISOL_MASK,1), (NONE_MASK,ISOL_MASK,2), (NONE_MASK,FIN3_MASK,5), (NONE_MASK,ISOL_MASK,6), ]
708];