sugarloaf 0.2.28

Sugarloaf is Rio rendering engine, designed to be multiplatform. It is based on WebGPU, Rust library for Desktops and WebAssembly for Web (JavaScript). This project is created and maintained for Rio terminal purposes but feel free to use it.
Documentation
// font_introspector was retired from https://github.com/dfrg/swash
// which is licensed under MIT license

use super::{cluster::Boundary, Codepoint, LineBreak, Properties, WordBreak};
use core::borrow::Borrow;

/// Returns an iterator yielding unicode properties and boundary analysis for
/// each character in the specified sequence.
pub fn analyze<I>(chars: I) -> Analyze<I::IntoIter>
where
    I: IntoIterator,
    I::IntoIter: Clone,
    I::Item: Borrow<char>,
{
    Analyze {
        chars: chars.into_iter(),
        state: BoundaryState::new(),
    }
}

/// Iterator that yields Unicode properties and boundary analysis.
/// This iterator is created by the [`analyze`] function.
#[derive(Clone)]
pub struct Analyze<I> {
    chars: I,
    state: BoundaryState,
}

impl<I> Iterator for Analyze<I>
where
    I: Iterator + Clone,
    I::Item: Borrow<char>,
{
    type Item = (Properties, Boundary);

    fn next(&mut self) -> Option<Self::Item> {
        self.state.next(&mut self.chars)
    }
}

impl<I> Analyze<I> {
    /// Returns true if the analysis indicates that bidi resolution is
    /// required.
    #[allow(unused)]
    pub fn needs_bidi_resolution(&self) -> bool {
        self.state.needs_bidi
    }
}

#[derive(Clone)]
struct BoundaryState {
    prev: WordBreak,
    prevent_next: bool,
    ri_count: u8,
    emoji: bool,
    next_emoji: bool,
    line_state: (u8, bool),
    first: bool,
    needs_bidi: bool,
}

impl BoundaryState {
    fn new() -> Self {
        Self {
            prev: WordBreak::EX,
            prevent_next: false,
            ri_count: 0,
            emoji: false,
            next_emoji: false,
            line_state: (sot, false),
            first: true,
            needs_bidi: false,
        }
    }

    fn reset_state(&mut self) {
        self.ri_count = 0;
        self.emoji = false;
    }

    fn check_word<I>(&mut self, props: Properties, iter: &mut I) -> bool
    where
        I: Iterator + Clone,
        I::Item: Borrow<char>,
    {
        use WordBreak::*;
        let b = props.word_break();
        let emoji = props.is_extended_pictographic();
        if self.first {
            self.first = false;
            self.prev = b;
            self.next_emoji = emoji;
            if b == RI {
                self.ri_count = 1;
            }
            return true;
        }
        let prev_emoji = self.emoji;
        self.emoji = self.emoji || self.next_emoji;
        self.next_emoji = emoji;
        let a = self.prev;
        self.prev = b;
        if self.prevent_next {
            self.prevent_next = false;
            return false;
        }
        if a == CR && b == LF {
            self.reset_state();
            return false;
        }
        let a_mask = a.mask();
        let b_mask = b.mask();
        const AH_LETTER: u32 = LE.mask() | HL.mask();
        const MID_NUM_LET_Q: u32 = MB.mask() | SQ.mask();
        const WB3_A: u32 = NL.mask() | CR.mask() | LF.mask();
        if a_mask & WB3_A != 0 || b_mask & WB3_A != 0 {
            // (Newline | CR | LF) ÷
            // ÷ (Newline | CR | LF)
            self.reset_state();
            return true;
        }
        if a == ZWJ && emoji {
            self.reset_state();
            return false;
        }
        const WB_4: u32 = Extend.mask() | FO.mask() | ZWJ.mask();
        if b_mask & WB_4 != 0 {
            // Ignore format and extend characters
            self.reset_state();
            self.prev = a;
            return false;
        }
        if a == WSegSpace && b == WSegSpace {
            // WSegSpace × WSegSpace
            self.reset_state();
            return false;
        }
        if a_mask & AH_LETTER != 0 {
            // AHLetter × AHLetter
            // AHLetter × Numeric
            if b_mask & (AH_LETTER | NU.mask()) != 0 {
                self.reset_state();
                return false;
            }
            if b_mask & (ML.mask() | MID_NUM_LET_Q) != 0 {
                // AHLetter	× (MidLetter | MidNumLetQ) AHLetter
                // AHLetter (MidLetter | MidNumLetQ) × AHLetter
                if let Some(c) = iter
                    .clone()
                    .next()
                    .map(|p| p.borrow().properties().word_break())
                {
                    if c.mask() & AH_LETTER != 0 {
                        self.prevent_next = true;
                        self.reset_state();
                        return false;
                    }
                }
            }
        }
        if a == HL {
            if b == SQ {
                self.reset_state();
                return false;
            }
            if b == DQ {
                // Hebrew_Letter × Double_Quote Hebrew_Letter
                // Hebrew_Letter Double_Quote × Hebrew_Letter
                if let Some(c) = iter
                    .clone()
                    .next()
                    .map(|p| p.borrow().properties().word_break())
                {
                    if c == HL {
                        self.prevent_next = true;
                        self.reset_state();
                        return false;
                    }
                }
            }
        }
        if a_mask & NU.mask() != 0 {
            // Numeric × Numeric
            // Numeric × AHLetter
            if b_mask & (NU.mask() | AH_LETTER) != 0 {
                self.reset_state();
                return false;
            }
            if b_mask & (MN.mask() | MID_NUM_LET_Q) != 0 {
                if let Some(c) = iter
                    .clone()
                    .next()
                    .map(|p| p.borrow().properties().word_break())
                {
                    // Numeric (MidNum | MidNumLetQ) × Numeric
                    // Numeric × (MidNum | MidNumLetQ) Numeric
                    if c == NU {
                        self.prevent_next = true;
                        self.reset_state();
                        return false;
                    }
                }
            }
        }
        if a == KA && b == KA {
            // Katakana × Katakana
            self.reset_state();
            return false;
        }
        const WB13_A: u32 = AH_LETTER | NU.mask() | KA.mask() | EX.mask();
        if a_mask & WB13_A != 0 && b == EX {
            // (AHLetter | Numeric | Katakana | ExtendNumLet) ×	ExtendNumLet
            self.reset_state();
            return false;
        }
        const WB13_B: u32 = AH_LETTER | NU.mask() | KA.mask();
        if a == EX && b_mask & WB13_B != 0 {
            // ExtendNumLet × (AHLetter | Numeric | Katakana)
            self.reset_state();
            return false;
        }
        if prev_emoji && a == ZWJ && emoji {
            self.ri_count = 0;
            return false;
        }
        if self.ri_count == 2 {
            self.reset_state();
            if b == RI {
                self.ri_count = 1;
            }
            return true;
        }
        if b == RI {
            self.ri_count += 1;
            if a != RI {
                self.reset_state();
                self.ri_count = 1;
                return true;
            }
            self.emoji = false;
            return false;
        }
        self.reset_state();
        true
    }

    fn check_line(&mut self, props: Properties) -> Boundary {
        let state = self.line_state;
        let lb = props.line_break();
        let val = PAIR_TABLE[state.0 as usize][lb as usize];
        let mode = if val & MANDATORY_BREAK_BIT != 0 {
            Boundary::Mandatory
        } else if val & ALLOWED_BREAK_BIT != 0 && !state.1 {
            Boundary::Line
        } else {
            Boundary::None
        };
        self.line_state = (
            val & !(ALLOWED_BREAK_BIT | MANDATORY_BREAK_BIT),
            lb == LineBreak::ZWJ,
        );
        mode
    }

    fn next<I>(&mut self, iter: &mut I) -> Option<(Properties, Boundary)>
    where
        I: Iterator + Clone,
        I::Item: Borrow<char>,
    {
        let props = iter.next()?.borrow().properties();
        let mut boundary = self.check_line(props);
        let word = self.check_word(props, iter);
        if boundary as u16 == 0 && word {
            boundary = Boundary::Word;
        }
        self.needs_bidi = self.needs_bidi || props.bidi_class().needs_resolution();
        Some((props, boundary))
    }
}

const ALLOWED_BREAK_BIT: u8 = 0x80;
const MANDATORY_BREAK_BIT: u8 = 0x40;

#[allow(non_upper_case_globals)]
const sot: u8 = 44;

#[rustfmt::skip]
const PAIR_TABLE: [[u8; 44]; 53] = [
    [1,1,130,3,132,5,134,28,8,1,10,11,140,141,14,15,144,145,18,19,148,21,22,151,152,153,26,27,28,29,30,31,32,33,162,1,1,37,38,39,1,41,1,235,],
    [1,1,130,3,132,5,134,28,8,1,10,11,140,141,14,15,144,145,18,19,148,21,22,151,152,153,26,27,28,29,30,31,32,33,162,1,1,37,38,39,1,41,1,235,],
    [129,129,2,3,132,5,134,28,8,2,10,11,140,141,14,15,144,145,146,19,148,149,22,151,152,153,26,27,28,157,158,159,160,33,162,129,129,50,38,39,129,41,2,235,],
    [129,129,130,3,132,5,134,28,8,3,10,11,140,141,14,143,144,145,146,19,148,149,22,151,152,153,26,27,28,157,158,159,160,33,162,129,129,37,38,39,129,41,3,235,],
    [1,1,2,3,4,5,134,28,8,4,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1,1,37,38,39,1,41,4,235,],
    [193,193,194,195,196,197,198,220,200,193,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,193,193,229,230,231,193,233,193,235,],
    [129,129,130,131,132,5,134,156,8,6,10,11,140,141,14,15,144,145,146,147,148,149,22,151,152,153,26,27,156,157,158,159,160,33,162,129,129,37,38,39,129,41,6,235,],
    [129,129,130,3,132,5,134,28,8,28,10,11,140,141,14,15,144,145,146,19,148,149,22,151,152,153,26,27,28,157,158,159,160,33,162,129,129,37,38,39,129,41,28,235,],
    [129,129,130,3,132,5,134,28,8,8,10,11,140,141,14,15,144,145,146,19,148,149,22,151,152,153,26,27,28,157,158,31,32,33,162,129,129,48,38,39,129,41,8,235,],
    [1,1,130,3,132,5,134,28,8,9,10,11,140,141,14,15,144,145,18,19,148,21,22,151,152,153,26,27,28,29,30,31,32,33,162,1,1,37,38,39,1,41,9,235,],
    [1,1,130,3,132,5,134,28,8,10,10,11,140,141,14,15,144,145,18,19,148,149,22,151,152,153,26,27,28,29,158,31,32,33,162,1,1,49,38,39,1,41,10,235,],
    [193,193,194,195,196,197,198,220,200,193,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,26,219,220,221,222,223,224,225,226,193,193,229,230,231,193,233,193,235,],
    [129,129,130,3,132,5,134,28,8,12,10,11,140,13,14,15,144,145,146,19,148,21,22,151,152,153,26,27,28,157,158,31,160,33,162,129,129,37,38,39,129,41,12,235,],
    [129,129,130,3,132,5,134,28,8,13,10,11,140,141,14,15,144,145,146,19,148,21,22,151,152,153,26,27,28,157,158,31,160,33,162,129,129,37,38,39,129,41,13,235,],
    [129,129,130,3,132,5,134,28,8,14,10,11,140,141,14,15,144,145,146,19,148,21,22,151,152,153,26,27,28,157,158,159,160,33,162,129,129,37,38,39,129,41,14,235,],
    [1,1,2,3,4,5,6,28,8,15,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1,1,37,38,39,1,41,15,235,],
    [129,129,130,3,132,5,134,28,8,16,10,11,140,141,14,15,144,145,146,19,148,21,22,151,24,25,26,27,28,157,158,31,160,33,162,129,129,37,38,39,129,41,16,235,],
    [129,129,130,3,132,5,134,28,8,17,10,11,140,141,14,15,144,145,146,19,148,21,22,151,24,153,26,27,28,157,158,31,160,33,162,129,129,37,38,39,129,41,17,235,],
    [1,1,130,51,132,5,134,28,8,18,10,11,140,141,14,15,144,145,18,51,148,21,22,151,152,153,26,27,28,29,30,31,32,33,162,1,1,37,38,39,1,41,18,235,],
    [129,129,130,3,132,5,134,28,8,19,10,11,140,141,14,143,144,145,146,19,148,149,22,151,152,153,26,27,28,29,158,159,160,33,162,129,129,37,38,39,129,41,19,235,],
    [129,129,130,3,132,5,134,28,8,20,10,11,140,141,14,15,144,145,146,19,148,21,22,151,152,153,26,27,28,157,158,31,160,33,162,129,129,37,38,39,129,41,20,235,],
    [129,129,130,3,132,5,134,28,8,21,10,11,140,141,14,15,144,145,146,19,148,21,22,151,152,153,26,27,28,157,158,159,160,33,162,129,129,37,38,39,129,41,21,235,],
    [1,1,130,3,132,5,134,28,8,22,10,11,140,141,14,15,144,145,18,19,148,149,22,151,152,153,26,27,28,29,158,159,160,33,162,1,1,37,38,39,1,41,22,235,],
    [129,129,130,3,132,5,134,28,8,23,10,11,140,141,14,15,16,17,146,19,148,21,22,23,152,25,26,27,28,157,158,31,160,33,162,129,129,37,38,39,129,41,23,235,],
    [129,129,130,3,132,5,134,28,8,24,10,11,140,141,14,15,144,145,146,19,148,21,22,151,24,153,26,27,28,157,158,31,160,33,162,129,129,37,38,39,129,41,24,235,],
    [129,129,130,3,132,5,134,28,8,25,10,11,140,141,14,15,144,145,146,19,148,21,22,151,24,25,26,27,28,157,158,31,160,33,162,129,129,37,38,39,129,41,25,235,],
    [193,193,194,195,196,197,198,220,200,193,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,193,193,229,230,231,193,233,193,235,],
    [193,193,194,195,196,197,198,220,200,193,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,193,193,229,230,231,193,233,193,235,],
    [129,129,130,3,132,5,134,28,8,28,10,11,140,141,14,15,144,145,146,19,148,149,22,151,152,153,26,27,28,157,158,159,160,33,162,129,129,37,38,39,129,41,28,235,],
    [1,1,130,3,132,5,134,28,8,29,10,11,140,141,14,15,144,145,18,19,148,21,22,151,152,153,26,27,28,29,30,31,32,33,162,1,1,37,38,39,1,41,29,235,],
    [1,1,2,3,4,5,6,28,8,30,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1,1,46,38,39,1,41,30,235,],
    [1,1,130,3,132,5,134,28,8,31,10,11,140,141,14,15,144,145,18,19,148,149,22,151,152,153,26,27,28,29,30,159,160,33,162,1,1,37,38,39,1,41,31,235,],
    [1,1,130,3,132,5,134,28,8,32,10,11,12,13,14,15,16,17,18,19,20,149,22,23,24,25,26,27,28,29,30,159,160,33,162,1,1,37,38,39,1,41,32,235,],
    [1,1,2,3,4,5,6,28,8,33,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1,1,47,38,39,1,41,33,235,],
    [129,129,130,3,132,5,134,28,8,34,10,11,140,141,14,15,144,145,146,19,148,149,22,151,152,153,26,27,28,157,158,159,160,33,52,129,129,37,38,39,129,41,34,235,],
    [1,1,130,3,132,5,134,28,8,1,10,11,140,141,14,15,144,145,18,19,148,21,22,151,152,153,26,27,28,29,30,31,32,33,162,1,1,37,38,39,1,41,1,235,],
    [1,1,130,3,132,5,134,28,8,1,10,11,140,141,14,15,144,145,18,19,148,21,22,151,152,153,26,27,28,29,30,31,32,33,162,1,1,37,38,39,1,41,1,235,],
    [129,129,130,131,132,5,134,156,8,129,10,11,140,141,14,143,144,145,146,147,148,149,22,151,152,153,26,27,156,157,158,159,160,161,162,129,129,37,38,39,129,41,129,235,],
    [129,129,130,3,132,5,134,28,8,38,10,11,140,141,14,15,144,145,18,19,148,149,22,151,152,153,26,27,28,29,158,159,160,33,162,129,129,37,38,39,129,41,38,235,],
    [1,1,2,3,4,5,6,28,8,39,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1,1,37,38,39,1,41,39,235,],
    [1,1,130,3,132,5,134,28,8,1,10,11,140,141,14,15,144,145,18,19,148,21,22,151,152,153,26,27,28,29,30,31,32,33,162,1,1,37,38,39,1,41,1,235,],
    [129,129,130,131,132,5,134,156,136,129,138,11,140,141,142,143,144,145,146,147,148,149,150,151,152,153,26,27,156,157,158,159,160,161,162,129,129,45,166,167,129,41,129,235,],
    [1,1,130,3,132,5,134,28,8,42,10,11,140,141,14,15,144,145,18,19,148,21,22,151,152,153,26,27,28,29,30,31,32,33,162,1,1,37,38,39,1,41,42,235,],
    [129,129,130,3,132,5,134,28,8,129,10,11,140,141,14,143,144,145,146,19,148,149,22,151,152,153,26,27,28,157,158,159,160,33,162,129,129,37,38,39,129,41,129,235,],
    [1,1,2,3,4,5,6,28,8,1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1,1,37,38,39,1,41,1,43,],
    [129,129,130,131,132,5,134,156,136,129,138,11,140,141,142,143,144,145,146,147,148,149,150,151,152,153,26,27,156,157,158,159,160,161,162,129,129,45,166,167,129,41,129,235,],
    [1,1,2,3,4,5,6,28,8,1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1,1,46,38,39,1,41,1,235,],
    [129,129,130,131,132,5,134,156,8,129,10,11,140,141,14,143,144,145,146,147,148,149,22,151,152,153,26,27,156,157,30,159,160,161,162,129,129,47,38,39,129,41,129,235,],
    [129,129,130,131,132,5,134,28,8,129,10,11,140,141,14,143,144,145,146,147,148,149,22,151,152,153,26,27,28,157,158,159,160,161,162,129,129,48,38,39,129,41,129,235,],
    [129,129,130,131,132,5,134,28,8,129,10,11,140,141,14,143,144,145,146,147,148,149,22,151,152,153,26,27,28,157,158,159,160,161,162,129,129,49,38,39,129,41,129,235,],
    [129,129,2,131,132,5,134,156,8,129,10,11,140,141,14,143,144,145,146,147,148,149,22,151,152,153,26,27,156,157,158,159,160,161,162,129,129,50,38,39,129,41,129,235,],
    [1,1,2,3,4,5,134,28,8,51,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1,1,37,38,39,1,41,51,235,],
    [129,129,130,3,132,5,134,28,8,52,10,11,140,141,14,15,144,145,146,19,148,149,22,151,152,153,26,27,28,157,158,159,160,33,162,129,129,37,38,39,129,41,52,235,],
];