Skip to main content

harfrust/hb/ot/gpos/
mod.rs

1//! OpenType GPOS lookups.
2
3use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t;
4use read_fonts::{
5    tables::{gpos::ValueFormat, variations::DeltaSetIndex},
6    FontData,
7};
8
9mod cursive;
10mod mark;
11mod pair;
12mod single;
13
14#[allow(unused_assignments)]
15fn apply_value(
16    ctx: &mut hb_ot_apply_context_t,
17    idx: usize,
18    data: &FontData,
19    mut offset: usize,
20    format: ValueFormat,
21) -> Option<bool> {
22    let scale = ctx.scale;
23    let pos = &mut ctx.buffer.pos[idx];
24    let is_horizontal = ctx.buffer.direction.is_horizontal();
25    let mut worked = false;
26    macro_rules! read_value {
27        () => {{
28            let value = data.read_at::<i16>(offset).ok()? as i32;
29            worked |= value != 0;
30            offset += 2;
31            value
32        }};
33    }
34    if format.contains(ValueFormat::X_PLACEMENT) {
35        pos.x_offset += scale.scale_x(read_value!());
36    }
37    if format.contains(ValueFormat::Y_PLACEMENT) {
38        pos.y_offset += scale.scale_y(read_value!());
39    }
40    if format.contains(ValueFormat::X_ADVANCE) {
41        if is_horizontal {
42            pos.x_advance += scale.scale_x(read_value!());
43        } else {
44            offset += 2;
45        }
46    }
47    if format.contains(ValueFormat::Y_ADVANCE) {
48        if !is_horizontal {
49            pos.y_advance -= scale.scale_y(read_value!());
50        } else {
51            offset += 2;
52        }
53    }
54    if !format.intersects(ValueFormat::ANY_DEVICE_OR_VARIDX) {
55        return Some(worked);
56    }
57    if let Some(vs) = &ctx.face.ot_tables.var_store {
58        let coords = ctx.face.ot_tables.coords;
59        macro_rules! read_delta {
60            () => {{
61                let rec_offset = data.read_at::<u16>(offset).ok()? as usize;
62                offset += 2;
63                // Keep the delta fractional; scale_x_f rounds once, matching
64                // HarfBuzz's em_scalef (rounding whole font units first would
65                // lose up to half a unit).
66                let mut value = 0.0f32;
67                // Offset is nullable
68                if rec_offset != 0 {
69                    let format = data.read_at::<u16>(rec_offset + 4).ok()?;
70                    // DeltaFormat specifier for a VariationIndex table
71                    // See <https://learn.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables>
72                    const VARIATION_INDEX_FORMAT: u16 = 0x8000;
73                    if format == VARIATION_INDEX_FORMAT {
74                        let outer = data.read_at::<u16>(rec_offset).ok()?;
75                        let inner = data.read_at::<u16>(rec_offset + 2).ok()?;
76                        value = vs
77                            .compute_float_delta(DeltaSetIndex { outer, inner }, coords)
78                            .unwrap_or_default()
79                            .to_f64() as f32;
80                        worked |= value != 0.0;
81                    }
82                }
83                value
84            }};
85        }
86        if format.contains(ValueFormat::X_PLACEMENT_DEVICE) {
87            pos.x_offset += scale.scale_x_f(read_delta!());
88        }
89        if format.contains(ValueFormat::Y_PLACEMENT_DEVICE) {
90            pos.y_offset += scale.scale_y_f(read_delta!());
91        }
92        if format.contains(ValueFormat::X_ADVANCE_DEVICE) {
93            if is_horizontal {
94                pos.x_advance += scale.scale_x_f(read_delta!());
95            } else {
96                offset += 2;
97            }
98        }
99        if format.contains(ValueFormat::Y_ADVANCE_DEVICE) {
100            if !is_horizontal {
101                pos.y_advance -= scale.scale_y_f(read_delta!());
102            } else {
103                offset += 2;
104            }
105        }
106    }
107    Some(worked)
108}