Skip to main content

harfrust/hb/aat/
layout_common.rs

1use super::layout::DELETED_GLYPH;
2use super::map::RangeFlags;
3use crate::hb::buffer::{hb_buffer_t, HB_BUFFER_SCRATCH_FLAG_SHAPER0};
4use crate::hb::face::hb_font_t;
5use crate::hb::face::Scale;
6use crate::hb::hb_mask_t;
7use crate::hb::ot_layout_gsubgpos::MappingCache;
8use crate::hb::ot_shape_plan::hb_ot_shape_plan_t;
9use crate::U32Set;
10use read_fonts::tables::aat::*;
11use read_fonts::types::{FixedSize, GlyphId};
12
13pub const HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED: u32 = HB_BUFFER_SCRATCH_FLAG_SHAPER0;
14
15pub(crate) const START_OF_TEXT: u16 = 0;
16
17pub(crate) type ClassCache = MappingCache;
18
19pub(crate) fn get_class<T: bytemuck::AnyBitPattern + FixedSize>(
20    machine: &ExtendedStateTable<'_, T>,
21    glyph_id: GlyphId,
22    cache: &ClassCache,
23) -> u16 {
24    if let Some(klass) = cache.get(glyph_id.to_u32()) {
25        return klass as u16;
26    }
27    let klass = machine
28        .class(glyph_id)
29        .unwrap_or(class::OUT_OF_BOUNDS as u16);
30    cache.set(glyph_id.to_u32(), klass as u32);
31    klass
32}
33
34/// HB: hb_aat_apply_context_t
35///
36/// See <https://github.com/harfbuzz/harfbuzz/blob/2c22a65f0cb99544c36580b9703a43b5dc97a9e1/src/hb-aat-layout-common.hh#L108>
37#[doc(alias = "hb_aat_apply_context_t")]
38pub struct AatApplyContext<'a> {
39    pub plan: &'a hb_ot_shape_plan_t,
40    pub face: &'a hb_font_t<'a>,
41    pub scale: Scale,
42    pub buffer: &'a mut hb_buffer_t,
43    pub has_glyph_classes: bool,
44    pub range_flags: Option<&'a [RangeFlags]>,
45    pub subtable_flags: hb_mask_t,
46    pub(crate) buffer_is_reversed: bool,
47    // Caches
48    using_buffer_glyph_set: bool,
49    pub(crate) first_set: Option<&'a U32Set>,
50    pub(crate) second_set: Option<&'a U32Set>,
51    pub(crate) machine_class_cache: Option<&'a ClassCache>,
52    pub(crate) start_end_safe_to_break: u64,
53}
54
55impl<'a> AatApplyContext<'a> {
56    pub fn new(
57        plan: &'a hb_ot_shape_plan_t,
58        face: &'a hb_font_t<'a>,
59        scale: Scale,
60        buffer: &'a mut hb_buffer_t,
61    ) -> Self {
62        Self {
63            plan,
64            face,
65            scale,
66            buffer,
67            has_glyph_classes: face.ot_tables.has_glyph_classes(),
68            range_flags: None,
69            subtable_flags: 0,
70            buffer_is_reversed: false,
71            using_buffer_glyph_set: false,
72            first_set: None,
73            second_set: None,
74            machine_class_cache: None,
75            start_end_safe_to_break: 0,
76        }
77    }
78
79    #[inline(always)]
80    pub(crate) fn scale_x(&self, value: i32) -> i32 {
81        self.scale.scale_x(value)
82    }
83
84    #[inline(always)]
85    pub(crate) fn scale_y(&self, value: i32) -> i32 {
86        self.scale.scale_y(value)
87    }
88
89    pub(crate) fn reverse_buffer(&mut self) {
90        self.buffer.reverse();
91        self.buffer_is_reversed = !self.buffer_is_reversed;
92    }
93
94    pub(crate) fn setup_buffer_glyph_set(&mut self) {
95        self.using_buffer_glyph_set = self.buffer.len >= 4;
96
97        if self.using_buffer_glyph_set {
98            self.buffer.update_glyph_set();
99        }
100    }
101
102    pub(crate) fn buffer_intersects_machine(&self) -> bool {
103        if let Some(first_set) = &self.first_set {
104            if self.using_buffer_glyph_set {
105                return self.buffer.glyph_set.intersects_set(first_set);
106            }
107            for info in &self.buffer.info {
108                if first_set.contains(info.glyph_id) {
109                    return true;
110                }
111            }
112            false
113        } else {
114            true
115        }
116    }
117
118    pub fn output_glyph(&mut self, glyph: u32) {
119        if self.using_buffer_glyph_set {
120            self.buffer.glyph_set.insert(glyph);
121        }
122        if glyph == DELETED_GLYPH {
123            self.buffer.scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
124            self.buffer.cur_mut(0).set_aat_deleted();
125        } else {
126            if self.has_glyph_classes {
127                self.buffer
128                    .cur_mut(0)
129                    .set_glyph_props(self.face.ot_tables.glyph_props(glyph.into()));
130            }
131        }
132        self.buffer.output_glyph(glyph);
133    }
134
135    pub fn replace_glyph(&mut self, glyph: u32) {
136        if glyph == DELETED_GLYPH {
137            self.buffer.scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
138            self.buffer.cur_mut(0).set_aat_deleted();
139        }
140
141        if self.using_buffer_glyph_set {
142            self.buffer.glyph_set.insert(glyph);
143        }
144        if self.has_glyph_classes {
145            self.buffer
146                .cur_mut(0)
147                .set_glyph_props(self.face.ot_tables.glyph_props(glyph.into()));
148        }
149        self.buffer.replace_glyph(glyph);
150    }
151
152    pub fn delete_glyph(&mut self) {
153        self.buffer.scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
154        self.buffer.cur_mut(0).set_aat_deleted();
155        self.buffer.replace_glyph(DELETED_GLYPH);
156    }
157
158    pub fn replace_glyph_inplace(&mut self, i: usize, glyph: u32) {
159        self.buffer.info[i].glyph_id = glyph;
160        if glyph == DELETED_GLYPH {
161            self.buffer.scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
162            self.buffer.info[i].set_aat_deleted();
163        }
164        if self.using_buffer_glyph_set {
165            self.buffer.glyph_set.insert(glyph);
166        }
167        if self.has_glyph_classes {
168            self.buffer.info[i].set_glyph_props(self.face.ot_tables.glyph_props(glyph.into()));
169        }
170    }
171}
172
173pub trait TypedCollectGlyphs<T: LookupValue> {
174    /// Add all indices into `set`.
175    fn collect_glyphs(&self, set: &mut U32Set, num_glyphs: u32) {
176        self.collect_glyphs_filtered::<_>(set, num_glyphs, |_| true);
177    }
178
179    /// For each valid index, read the value of type `T`.
180    /// If `filter(&value)` returns true, insert the index into `set`.
181    fn collect_glyphs_filtered<F>(&self, _set: &mut U32Set, _num_glyphs: u32, _filter: F)
182    where
183        F: Fn(T) -> bool;
184}
185
186impl<T> TypedCollectGlyphs<T> for TypedLookup<'_, T>
187where
188    T: LookupValue,
189{
190    fn collect_glyphs(&self, set: &mut U32Set, num_glyphs: u32) {
191        self.lookup.collect_glyphs::<T>(set, num_glyphs);
192    }
193    fn collect_glyphs_filtered<F>(&self, set: &mut U32Set, num_glyphs: u32, filter: F)
194    where
195        F: Fn(T) -> bool,
196    {
197        self.lookup
198            .collect_glyphs_filtered::<T, F>(set, num_glyphs, filter);
199    }
200}
201
202pub trait CollectGlyphs {
203    /// Add all indices into `set`.
204    fn collect_glyphs<T>(&self, set: &mut U32Set, num_glyphs: u32)
205    where
206        T: LookupValue,
207    {
208        self.collect_glyphs_filtered::<T, _>(set, num_glyphs, |_| true);
209    }
210
211    /// For each valid index, read the value of type `T`.
212    /// If `filter(&value)` returns true, insert the index into `set`.
213    fn collect_glyphs_filtered<T, F>(&self, _set: &mut U32Set, _num_glyphs: u32, _filter: F)
214    where
215        T: LookupValue,
216        F: Fn(T) -> bool;
217}
218
219impl CollectGlyphs for Lookup<'_> {
220    fn collect_glyphs<T>(&self, set: &mut U32Set, num_glyphs: u32)
221    where
222        T: LookupValue,
223    {
224        match self {
225            Lookup::Format0(lookup) => lookup.collect_glyphs::<T>(set, num_glyphs),
226            Lookup::Format2(lookup) => lookup.collect_glyphs::<T>(set, num_glyphs),
227            Lookup::Format4(lookup) => lookup.collect_glyphs::<T>(set, num_glyphs),
228            Lookup::Format6(lookup) => lookup.collect_glyphs::<T>(set, num_glyphs),
229            Lookup::Format8(lookup) => lookup.collect_glyphs::<T>(set, num_glyphs),
230            Lookup::Format10(lookup) => lookup.collect_glyphs::<T>(set, num_glyphs),
231        }
232    }
233    fn collect_glyphs_filtered<T, F>(&self, set: &mut U32Set, num_glyphs: u32, filter: F)
234    where
235        T: LookupValue,
236        F: Fn(T) -> bool,
237    {
238        match self {
239            Lookup::Format0(lookup) => {
240                lookup.collect_glyphs_filtered::<T, F>(set, num_glyphs, filter);
241            }
242            Lookup::Format2(lookup) => {
243                lookup.collect_glyphs_filtered::<T, F>(set, num_glyphs, filter);
244            }
245            Lookup::Format4(lookup) => {
246                lookup.collect_glyphs_filtered::<T, F>(set, num_glyphs, filter);
247            }
248            Lookup::Format6(lookup) => {
249                lookup.collect_glyphs_filtered::<T, F>(set, num_glyphs, filter);
250            }
251            Lookup::Format8(lookup) => {
252                lookup.collect_glyphs_filtered::<T, F>(set, num_glyphs, filter);
253            }
254            Lookup::Format10(lookup) => {
255                lookup.collect_glyphs_filtered::<T, F>(set, num_glyphs, filter);
256            }
257        }
258    }
259}
260
261impl CollectGlyphs for Lookup0<'_> {
262    fn collect_glyphs<T>(&self, set: &mut U32Set, num_glyphs: u32)
263    where
264        T: LookupValue,
265    {
266        set.insert_range(0..=num_glyphs.saturating_sub(1));
267    }
268    fn collect_glyphs_filtered<T, F>(&self, set: &mut U32Set, num_glyphs: u32, filter: F)
269    where
270        T: LookupValue,
271        F: Fn(T) -> bool,
272    {
273        if let Ok(values) = self.values::<T>() {
274            for (i, value) in values.iter().take(num_glyphs as usize).enumerate() {
275                if filter(value.get()) {
276                    set.insert(i as u32);
277                }
278            }
279        }
280    }
281}
282impl CollectGlyphs for Lookup2<'_> {
283    fn collect_glyphs_filtered<T, F>(&self, set: &mut U32Set, _num_glyphs: u32, filter: F)
284    where
285        T: LookupValue,
286        F: Fn(T) -> bool,
287    {
288        if let Ok(segments) = self.segments::<T>() {
289            for segment in segments {
290                let value = segment.value;
291                if filter(value.get()) {
292                    if segment.first_glyph.get() as u32 == DELETED_GLYPH {
293                        continue;
294                    }
295                    set.insert_range(
296                        segment.first_glyph.get() as u32..=segment.last_glyph.get() as u32,
297                    );
298                }
299            }
300        }
301    }
302}
303impl CollectGlyphs for Lookup4<'_> {
304    fn collect_glyphs<T>(&self, set: &mut U32Set, _num_glyphs: u32)
305    where
306        T: LookupValue,
307    {
308        for segment in self.segments() {
309            if segment.first_glyph.get() as u32 == DELETED_GLYPH {
310                continue;
311            }
312            set.insert_range(segment.first_glyph.get() as u32..=segment.last_glyph.get() as u32);
313        }
314    }
315    fn collect_glyphs_filtered<T, F>(&self, set: &mut U32Set, _num_glyphs: u32, filter: F)
316    where
317        T: LookupValue,
318        F: Fn(T) -> bool,
319    {
320        for (segment_idx, segment) in self.segments().iter().enumerate() {
321            if segment.first_glyph.get() as u32 == DELETED_GLYPH {
322                continue;
323            }
324            let segment_values = self.segment_values(segment_idx);
325            if let Ok(segment_values) = segment_values {
326                for (i, value) in segment_values.iter().enumerate() {
327                    if filter(value.get()) {
328                        set.insert(segment.first_glyph.get() as u32 + i as u32);
329                    }
330                }
331            }
332        }
333    }
334}
335impl CollectGlyphs for Lookup6<'_> {
336    fn collect_glyphs_filtered<T, F>(&self, set: &mut U32Set, _num_glyphs: u32, filter: F)
337    where
338        T: LookupValue,
339        F: Fn(T) -> bool,
340    {
341        let entries = self.entries();
342        if let Ok(entries) = entries {
343            for entry in entries {
344                let value = entry.value;
345                if filter(value.get()) {
346                    if entry.glyph.get() as u32 == DELETED_GLYPH {
347                        continue;
348                    }
349                    set.insert(entry.glyph.get() as u32);
350                }
351            }
352        }
353    }
354}
355impl CollectGlyphs for Lookup8<'_> {
356    fn collect_glyphs<T>(&self, set: &mut U32Set, _num_glyphs: u32)
357    where
358        T: LookupValue,
359    {
360        let n_values = self.value_array().len();
361        let first_glyph = self.first_glyph();
362        if first_glyph as u32 == DELETED_GLYPH {
363            return;
364        }
365        set.insert_range(
366            first_glyph as u32..=first_glyph as u32 + n_values.saturating_sub(1) as u32,
367        );
368    }
369    fn collect_glyphs_filtered<T, F>(&self, set: &mut U32Set, _num_glyphs: u32, filter: F)
370    where
371        T: LookupValue,
372        F: Fn(T) -> bool,
373    {
374        let values = self.value_array();
375        let first_glyph = self.first_glyph();
376        if first_glyph as u32 == DELETED_GLYPH {
377            return;
378        }
379        for (i, value) in values.iter().enumerate() {
380            if filter(T::from_u16(value.get())) {
381                set.insert(first_glyph as u32 + i as u32);
382            }
383        }
384    }
385}
386impl CollectGlyphs for Lookup10<'_> {
387    fn collect_glyphs<T>(&self, set: &mut U32Set, _num_glyphs: u32)
388    where
389        T: LookupValue,
390    {
391        let n_values = self.glyph_count();
392        let first_glyph = self.first_glyph();
393        if first_glyph as u32 == DELETED_GLYPH {
394            return;
395        }
396        set.insert_range(
397            first_glyph as u32..=first_glyph as u32 + n_values.saturating_sub(1) as u32,
398        );
399    }
400    fn collect_glyphs_filtered<T, F>(&self, set: &mut U32Set, _num_glyphs: u32, filter: F)
401    where
402        T: LookupValue,
403        F: Fn(T) -> bool,
404    {
405        let first_glyph = self.first_glyph();
406        if first_glyph as u32 == DELETED_GLYPH {
407            return;
408        }
409        for i in 0..self.glyph_count() {
410            let idx = first_glyph as u32 + i as u32;
411            // TODO: Speed up by accessing the value array directly
412            let value = self.value::<T>(idx as u16);
413            if let Ok(value) = value {
414                if filter(value) {
415                    set.insert(idx);
416                }
417            }
418        }
419    }
420}