1
2
3
4
5
6
7
8
9
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
//! The lookup flag type.
//!
//! This is kind-of-but-not-quite-exactly a bit enumeration, and so we implement
//! it manually.

use core::ops::{BitOr, BitOrAssign};

/// The [LookupFlag](https://learn.microsoft.com/en-us/typography/opentype/spec/chapter2#lookupFlag) bit enumeration.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LookupFlag(u16);

//NOTE: this impl has the potential to make garbage if used on two lookupflag
//instances which have different mark attachment masks set, but as that field
//is not really used in compilation, which is where this impl will be helpful,
//the risk that this is the source of an actual bug seems very low,
impl BitOr for LookupFlag {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self::Output {
        Self(self.0 | rhs.0)
    }
}

impl BitOrAssign for LookupFlag {
    fn bitor_assign(&mut self, rhs: Self) {
        self.0 |= rhs.0
    }
}

impl LookupFlag {
    /// This bit relates only to the correct processing of GPOS type 3 (cursive attachment) lookups
    ///
    /// When this bit is set, the last glyph in a given sequence to which the cursive
    /// attachment lookup is applied, will be positioned on the baseline.
    pub const RIGHT_TO_LEFT: Self = LookupFlag(0x0001);
    /// If set, skips over base glyphs
    pub const IGNORE_BASE_GLYPHS: Self = LookupFlag(0x002);
    /// If set, skips over ligatures
    pub const IGNORE_LIGATURES: Self = LookupFlag(0x004);
    /// If set, skips over all combining marks
    pub const IGNORE_MARKS: Self = LookupFlag(0x008);
    /// If set, indicates that the lookup table structure is followed by a MarkFilteringSet field.
    ///
    /// The layout engine skips over all mark glyphs not in the mark filtering set indicated.
    pub const USE_MARK_FILTERING_SET: Self = LookupFlag(0x010);

    /// Return new, empty flags
    pub fn empty() -> Self {
        Self(0)
    }

    /// Construct a LookupFlag from a raw value, discarding invalid bits
    pub fn from_bits_truncate(bits: u16) -> Self {
        const VALID_BITS: u16 = !0x00E0;
        Self(bits & VALID_BITS)
    }

    /// Raw transmutation to u16.
    pub fn to_bits(self) -> u16 {
        self.0
    }

    /// This bit relates only to the correct processing of the cursive attachment
    /// lookup type (GPOS lookup type 3).
    ///
    /// When this bit is set, the last glyph in a given sequence to which the
    /// cursive attachment lookup is applied, will be positioned on the baseline.
    pub fn right_to_left(self) -> bool {
        (self.0 & 0x0001) != 0
    }

    /// This bit relates only to the correct processing of the cursive attachment
    /// lookup type (GPOS lookup type 3).
    ///
    /// When this bit is set, the last glyph in a given sequence to which the
    /// cursive attachment lookup is applied, will be positioned on the baseline.
    pub fn set_right_to_left(&mut self, val: bool) {
        if val {
            self.0 |= 0x0001
        } else {
            self.0 &= !0x0001
        }
    }

    /// If set, skips over base glyphs
    pub fn ignore_base_glyphs(self) -> bool {
        (self.0 & 0x0002) != 0
    }

    /// If set, skips over base glyphs
    pub fn set_ignore_base_glyphs(&mut self, val: bool) {
        if val {
            self.0 |= 0x0002
        } else {
            self.0 &= !0x0002
        }
    }

    /// If set, skips over ligatures
    pub fn ignore_ligatures(self) -> bool {
        (self.0 & 0x0004) != 0
    }

    /// If set, skips over ligatures
    pub fn set_ignore_ligatures(&mut self, val: bool) {
        if val {
            self.0 |= 0x0004
        } else {
            self.0 &= !0x0004
        }
    }

    /// If set, skips over all combining marks
    pub fn ignore_marks(self) -> bool {
        (self.0 & 0x0008) != 0
    }

    /// If set, skips over all combining marks
    pub fn set_ignore_marks(&mut self, val: bool) {
        if val {
            self.0 |= 0x0008
        } else {
            self.0 &= !0x0008
        }
    }

    /// If set, indicates that the lookup table structure is followed by a
    /// MarkFilteringSet field.
    ///
    /// The layout engine skips over all mark glyphs not in the mark filtering set
    /// indicated.
    pub fn use_mark_filtering_set(self) -> bool {
        (self.0 & 0x0010) != 0
    }

    /// If set, indicates that the lookup table structure is followed by a
    /// MarkFilteringSet field.
    ///
    /// The layout engine skips over all mark glyphs not in the mark filtering set
    /// indicated.
    pub fn set_use_mark_filtering_set(&mut self, val: bool) {
        if val {
            self.0 |= 0x0010
        } else {
            self.0 &= !0x0010
        }
    }

    /// If not zero, skips over all marks of attachment type different from specified.
    pub fn mark_attachment_type_mask(self) -> Option<u16> {
        let val = self.0 & 0xff00;
        if val == 0 {
            None
        } else {
            Some(val >> 8)
        }
    }

    /// If not zero, skips over all marks of attachment type different from specified.
    pub fn set_mark_attachment_type(&mut self, val: u16) {
        let val = (val & 0xff) << 8;
        self.0 = (self.0 & 0xff) | val;
    }
}

impl types::Scalar for LookupFlag {
    type Raw = <u16 as types::Scalar>::Raw;
    fn to_raw(self) -> Self::Raw {
        self.0.to_raw()
    }
    fn from_raw(raw: Self::Raw) -> Self {
        let t = <u16>::from_raw(raw);
        Self(t)
    }
}