Coverage Report

Created: 2026-10-24 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/read-fonts-0.46.0/src/tables/variations.rs
Line
Count
Source
1
//! OpenType font variations common tables.
2
3
include!("../../generated/generated_variations.rs");
4
5
use super::{
6
    glyf::{PointCoord, PointFlags, PointMarker},
7
    gvar::GlyphDelta,
8
};
9
10
pub const NO_VARIATION_INDEX: u32 = 0xFFFFFFFF;
11
/// Outer and inner indices for reading from an [ItemVariationStore].
12
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
13
pub struct DeltaSetIndex {
14
    /// Outer delta set index.
15
    pub outer: u16,
16
    /// Inner delta set index.
17
    pub inner: u16,
18
}
19
20
impl DeltaSetIndex {
21
    pub const NO_VARIATION_INDEX: Self = Self {
22
        outer: (NO_VARIATION_INDEX >> 16) as u16,
23
        inner: (NO_VARIATION_INDEX & 0xFFFF) as u16,
24
    };
25
}
26
27
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
28
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29
pub struct TupleIndex(u16);
30
31
impl TupleIndex {
32
    /// Flag indicating that this tuple variation header includes an embedded
33
    /// peak tuple record, immediately after the tupleIndex field.
34
    ///
35
    /// If set, the low 12 bits of the tupleIndex value are ignored.
36
    ///
37
    /// Note that this must always be set within the 'cvar' table.
38
    pub const EMBEDDED_PEAK_TUPLE: u16 = 0x8000;
39
40
    /// Flag indicating that this tuple variation table applies to an
41
    /// intermediate region within the variation space.
42
    ///
43
    /// If set, the header includes the two intermediate-region, start and end
44
    /// tuple records, immediately after the peak tuple record (if present).
45
    pub const INTERMEDIATE_REGION: u16 = 0x4000;
46
    /// Flag indicating that the serialized data for this tuple variation table
47
    /// includes packed “point” number data.
48
    ///
49
    /// If set, this tuple variation table uses that number data; if clear,
50
    /// this tuple variation table uses shared number data found at the start
51
    /// of the serialized data for this glyph variation data or 'cvar' table.
52
    pub const PRIVATE_POINT_NUMBERS: u16 = 0x2000;
53
    //0x1000  Reserved  Reserved for future use — set to 0.
54
    //
55
    /// Mask for the low 12 bits to give the shared tuple records index.
56
    pub const TUPLE_INDEX_MASK: u16 = 0x0FFF;
57
58
    #[inline(always)]
59
45.2k
    fn tuple_len(self, axis_count: u16, flag: usize) -> usize {
60
45.2k
        if flag == 0 {
61
21.7k
            self.embedded_peak_tuple() as usize * axis_count as usize
62
        } else {
63
23.4k
            self.intermediate_region() as usize * axis_count as usize
64
        }
65
45.2k
    }
66
67
0
    pub fn bits(self) -> u16 {
68
0
        self.0
69
0
    }
70
71
0
    pub fn from_bits(bits: u16) -> Self {
72
0
        TupleIndex(bits)
73
0
    }
74
75
    /// `true` if the header includes an embedded peak tuple.
76
81.7k
    pub fn embedded_peak_tuple(self) -> bool {
77
81.7k
        (self.0 & Self::EMBEDDED_PEAK_TUPLE) != 0
78
81.7k
    }
79
80
    /// `true` if the header includes the two intermediate region tuple records.
81
77.3k
    pub fn intermediate_region(self) -> bool {
82
77.3k
        (self.0 & Self::INTERMEDIATE_REGION) != 0
83
77.3k
    }
84
85
    /// `true` if the data for this table includes packed point number data.
86
3.44k
    pub fn private_point_numbers(self) -> bool {
87
3.44k
        (self.0 & Self::PRIVATE_POINT_NUMBERS) != 0
88
3.44k
    }
89
90
26.7k
    pub fn tuple_records_index(self) -> Option<u16> {
91
26.7k
        (!self.embedded_peak_tuple()).then_some(self.0 & Self::TUPLE_INDEX_MASK)
92
26.7k
    }
93
}
94
95
impl types::Scalar for TupleIndex {
96
    type Raw = <u16 as types::Scalar>::Raw;
97
0
    fn to_raw(self) -> Self::Raw {
98
0
        self.0.to_raw()
99
0
    }
100
135k
    fn from_raw(raw: Self::Raw) -> Self {
101
135k
        let t = <u16>::from_raw(raw);
102
135k
        Self(t)
103
135k
    }
104
}
105
106
/// The 'tupleVariationCount' field of the [Tuple Variation Store Header][header]
107
///
108
/// The high 4 bits are flags, and the low 12 bits are the number of tuple
109
/// variation tables for this glyph. The count can be any number between 1 and 4095.
110
///
111
/// [header]: https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuple-variation-store-header
112
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
113
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
114
pub struct TupleVariationCount(u16);
115
116
impl TupleVariationCount {
117
    /// Flag indicating that some or all tuple variation tables reference a
118
    /// shared set of “point” numbers.
119
    ///
120
    /// These shared numbers are represented as packed point number data at the
121
    /// start of the serialized data.
122
    pub const SHARED_POINT_NUMBERS: u16 = 0x8000;
123
124
    /// Mask for the low 12 bits to give the shared tuple records index.
125
    pub const COUNT_MASK: u16 = 0x0FFF;
126
127
0
    pub fn bits(self) -> u16 {
128
0
        self.0
129
0
    }
130
131
0
    pub fn from_bits(bits: u16) -> Self {
132
0
        Self(bits)
133
0
    }
134
135
    /// `true` if any tables reference a shared set of point numbers
136
2.51k
    pub fn shared_point_numbers(self) -> bool {
137
2.51k
        (self.0 & Self::SHARED_POINT_NUMBERS) != 0
138
2.51k
    }
139
140
2.51k
    pub fn count(self) -> u16 {
141
2.51k
        self.0 & Self::COUNT_MASK
142
2.51k
    }
143
}
144
145
impl types::Scalar for TupleVariationCount {
146
    type Raw = <u16 as types::Scalar>::Raw;
147
0
    fn to_raw(self) -> Self::Raw {
148
0
        self.0.to_raw()
149
0
    }
150
2.68k
    fn from_raw(raw: Self::Raw) -> Self {
151
2.68k
        let t = <u16>::from_raw(raw);
152
2.68k
        Self(t)
153
2.68k
    }
154
}
155
156
impl<'a> TupleVariationHeader<'a> {
157
    /// Peak tuple record for this tuple variation table — optional,
158
    /// determined by flags in the tupleIndex value.  Note that this
159
    /// must always be included in the 'cvar' table.
160
    #[inline(always)]
161
6.13k
    pub fn peak_tuple(&self) -> Option<Tuple<'a>> {
162
6.13k
        self.tuple_index().embedded_peak_tuple().then(|| {
163
6.13k
            let range = self.peak_tuple_byte_range();
164
6.13k
            Tuple {
165
6.13k
                values: self.offset_data().read_array(range).unwrap(),
166
6.13k
            }
167
6.13k
        })
168
6.13k
    }
169
170
    /// Intermediate start tuple record for this tuple variation table
171
    /// — optional, determined by flags in the tupleIndex value.
172
    #[inline(always)]
173
0
    pub fn intermediate_start_tuple(&self) -> Option<Tuple<'a>> {
174
0
        self.tuple_index().intermediate_region().then(|| {
175
0
            let range = self.intermediate_start_tuple_byte_range();
176
0
            Tuple {
177
0
                values: self.offset_data().read_array(range).unwrap(),
178
0
            }
179
0
        })
180
0
    }
181
182
    /// Intermediate end tuple record for this tuple variation table
183
    /// — optional, determined by flags in the tupleIndex value.
184
    #[inline(always)]
185
0
    pub fn intermediate_end_tuple(&self) -> Option<Tuple<'a>> {
186
0
        self.tuple_index().intermediate_region().then(|| {
187
0
            let range = self.intermediate_end_tuple_byte_range();
188
0
            Tuple {
189
0
                values: self.offset_data().read_array(range).unwrap(),
190
0
            }
191
0
        })
192
0
    }
193
194
    /// Intermediate tuple records for this tuple variation table
195
    /// — optional, determined by flags in the tupleIndex value.
196
    #[inline(always)]
197
26.7k
    pub fn intermediate_tuples(&self) -> Option<(Tuple<'a>, Tuple<'a>)> {
198
26.7k
        self.tuple_index().intermediate_region().then(|| {
199
7.82k
            let start_range = self.intermediate_start_tuple_byte_range();
200
7.82k
            let end_range = self.intermediate_end_tuple_byte_range();
201
7.82k
            (
202
7.82k
                Tuple {
203
7.82k
                    values: self.offset_data().read_array(start_range).unwrap(),
204
7.82k
                },
205
7.82k
                Tuple {
206
7.82k
                    values: self.offset_data().read_array(end_range).unwrap(),
207
7.82k
                },
208
7.82k
            )
209
7.82k
        })
210
26.7k
    }
211
212
    /// Compute the actual length of this table in bytes
213
    #[inline(always)]
214
27.1k
    fn byte_len(&self, axis_count: u16) -> usize {
215
        const FIXED_LEN: usize = u16::RAW_BYTE_LEN + TupleIndex::RAW_BYTE_LEN;
216
27.1k
        let tuple_byte_len = F2Dot14::RAW_BYTE_LEN * axis_count as usize;
217
27.1k
        let index = self.tuple_index();
218
        FIXED_LEN
219
27.1k
            + if index.embedded_peak_tuple() {
220
6.32k
                tuple_byte_len
221
            } else {
222
20.7k
                Default::default()
223
            }
224
27.1k
            + if index.intermediate_region() {
225
8.16k
                tuple_byte_len * 2
226
            } else {
227
18.9k
                Default::default()
228
            }
229
27.1k
    }
230
}
231
232
impl Tuple<'_> {
233
10.0k
    pub fn len(&self) -> usize {
234
10.0k
        self.values().len()
235
10.0k
    }
236
237
0
    pub fn is_empty(&self) -> bool {
238
0
        self.values.is_empty()
239
0
    }
240
241
    #[inline(always)]
242
26.3k
    pub fn get(&self, idx: usize) -> Option<F2Dot14> {
243
26.3k
        self.values.get(idx).map(BigEndian::get)
244
26.3k
    }
245
}
246
247
//FIXME: add an #[extra_traits(..)] attribute!
248
#[allow(clippy::derivable_impls)]
249
impl Default for Tuple<'_> {
250
0
    fn default() -> Self {
251
0
        Self {
252
0
            values: Default::default(),
253
0
        }
254
0
    }
255
}
256
257
/// [Packed "Point" Numbers](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-point-numbers)
258
#[derive(Clone, Default, Debug)]
259
pub struct PackedPointNumbers<'a> {
260
    data: FontData<'a>,
261
}
262
263
impl<'a> PackedPointNumbers<'a> {
264
    /// read point numbers off the front of this data, returning the remaining data
265
2.96k
    pub fn split_off_front(data: FontData<'a>) -> (Self, FontData<'a>) {
266
2.96k
        let this = PackedPointNumbers { data };
267
2.96k
        let total_len = this.total_len();
268
2.96k
        let remainder = data.split_off(total_len).unwrap_or_default();
269
2.96k
        (this, remainder)
270
2.96k
    }
271
272
    /// The number of points in this set
273
2.94k
    pub fn count(&self) -> u16 {
274
2.94k
        self.count_and_count_bytes().0
275
2.94k
    }
276
277
    /// compute the count, and the number of bytes used to store it
278
8.13k
    fn count_and_count_bytes(&self) -> (u16, usize) {
279
8.13k
        match self.data.read_at::<u8>(0).unwrap_or(0) {
280
2.92k
            0 => (0, 1),
281
5.20k
            count @ 1..=127 => (count as u16, 1),
282
            _ => {
283
                // "If the high bit of the first byte is set, then a second byte is used.
284
                // The count is read from interpreting the two bytes as a big-endian
285
                // uint16 value with the high-order bit masked out."
286
287
586
                let count = self.data.read_at::<u16>(0).unwrap_or_default() & 0x7FFF;
288
                // a weird case where I'm following fonttools: if the 'use words' bit
289
                // is set, but the total count is still 0, treat it like 0 first byte
290
586
                if count == 0 {
291
206
                    (0, 2)
292
                } else {
293
380
                    (count & 0x7FFF, 2)
294
                }
295
            }
296
        }
297
8.13k
    }
298
299
    /// the number of bytes to encode the packed point numbers
300
    #[inline(never)]
301
2.96k
    fn total_len(&self) -> usize {
302
2.96k
        let (n_points, mut n_bytes) = self.count_and_count_bytes();
303
2.96k
        if n_points == 0 {
304
1.44k
            return n_bytes;
305
1.51k
        }
306
1.51k
        let mut cursor = self.data.cursor();
307
1.51k
        cursor.advance_by(n_bytes);
308
309
1.51k
        let mut n_seen = 0;
310
5.96k
        while n_seen < n_points {
311
4.66k
            let Some((count, two_bytes)) = read_control_byte(&mut cursor) else {
312
206
                return n_bytes;
313
            };
314
4.45k
            let word_size = 1 + usize::from(two_bytes);
315
4.45k
            let run_size = word_size * count as usize;
316
4.45k
            n_bytes += run_size + 1; // plus the control byte;
317
4.45k
            cursor.advance_by(run_size);
318
4.45k
            n_seen += count as u16;
319
        }
320
321
1.30k
        n_bytes
322
2.96k
    }
323
324
    /// Iterate over the packed points
325
2.23k
    pub fn iter(&self) -> PackedPointNumbersIter<'a> {
326
2.23k
        let (count, n_bytes) = self.count_and_count_bytes();
327
2.23k
        let mut cursor = self.data.cursor();
328
2.23k
        cursor.advance_by(n_bytes);
329
2.23k
        PackedPointNumbersIter::new(count, cursor)
330
2.23k
    }
331
}
332
333
/// An iterator over the packed point numbers data.
334
#[derive(Clone, Debug)]
335
pub struct PackedPointNumbersIter<'a> {
336
    count: u16,
337
    seen: u16,
338
    last_val: u16,
339
    current_run: PointRunIter<'a>,
340
}
341
342
impl<'a> PackedPointNumbersIter<'a> {
343
2.23k
    fn new(count: u16, cursor: Cursor<'a>) -> Self {
344
2.23k
        PackedPointNumbersIter {
345
2.23k
            count,
346
2.23k
            seen: 0,
347
2.23k
            last_val: 0,
348
2.23k
            current_run: PointRunIter {
349
2.23k
                remaining: 0,
350
2.23k
                two_bytes: false,
351
2.23k
                cursor,
352
2.23k
            },
353
2.23k
        }
354
2.23k
    }
355
}
356
357
/// Implements the logic for iterating over the individual runs
358
#[derive(Clone, Debug)]
359
struct PointRunIter<'a> {
360
    remaining: u8,
361
    two_bytes: bool,
362
    cursor: Cursor<'a>,
363
}
364
365
impl Iterator for PointRunIter<'_> {
366
    type Item = u16;
367
368
25.9k
    fn next(&mut self) -> Option<Self::Item> {
369
        // if no items remain in this run, start the next one.
370
29.9k
        while self.remaining == 0 {
371
4.09k
            (self.remaining, self.two_bytes) = read_control_byte(&mut self.cursor)?;
372
        }
373
374
25.8k
        self.remaining -= 1;
375
25.8k
        if self.two_bytes {
376
1.34k
            self.cursor.read().ok()
377
        } else {
378
24.5k
            self.cursor.read::<u8>().ok().map(|v| v as u16)
379
        }
380
25.9k
    }
381
}
382
383
/// returns the count and the 'uses_two_bytes' flag from the control byte
384
8.75k
fn read_control_byte(cursor: &mut Cursor) -> Option<(u8, bool)> {
385
8.75k
    let control: u8 = cursor.read().ok()?;
386
8.49k
    let two_bytes = (control & 0x80) != 0;
387
8.49k
    let count = (control & 0x7F) + 1;
388
8.49k
    Some((count, two_bytes))
389
8.75k
}
390
391
impl Iterator for PackedPointNumbersIter<'_> {
392
    type Item = u16;
393
394
99.2k
    fn next(&mut self) -> Option<Self::Item> {
395
        // if our count is zero, we keep incrementing forever
396
99.2k
        if self.count == 0 {
397
72.7k
            let result = self.last_val;
398
72.7k
            self.last_val = self.last_val.checked_add(1)?;
399
72.7k
            return Some(result);
400
26.4k
        }
401
402
26.4k
        if self.count == self.seen {
403
576
            return None;
404
25.9k
        }
405
25.9k
        self.seen += 1;
406
25.9k
        self.last_val = self.last_val.checked_add(self.current_run.next()?)?;
407
25.4k
        Some(self.last_val)
408
99.2k
    }
409
410
0
    fn size_hint(&self) -> (usize, Option<usize>) {
411
0
        (self.count as usize, Some(self.count as usize))
412
0
    }
413
}
414
415
// completely unnecessary?
416
impl ExactSizeIterator for PackedPointNumbersIter<'_> {}
417
418
/// [Packed Deltas](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-deltas)
419
#[derive(Clone, Debug)]
420
pub struct PackedDeltas<'a> {
421
    data: FontData<'a>,
422
    // How many values we expect
423
    count: Option<usize>,
424
}
425
426
impl<'a> PackedDeltas<'a> {
427
308
    pub(crate) fn new(data: FontData<'a>, count: usize) -> Self {
428
308
        Self {
429
308
            data,
430
308
            count: Some(count),
431
308
        }
432
308
    }
433
434
    /// NOTE: this is unbounded, and assumes all of data is deltas.
435
    #[doc(hidden)] // used by tests in write-fonts
436
553
    pub fn consume_all(data: FontData<'a>) -> Self {
437
553
        Self { data, count: None }
438
553
    }
439
440
0
    pub fn count(&self) -> Option<usize> {
441
0
        self.count
442
0
    }
443
444
1.72k
    pub fn count_or_compute(&self) -> usize {
445
1.72k
        self.count.unwrap_or_else(|| count_all_deltas(self.data))
446
1.72k
    }
447
448
0
    pub fn iter(&self) -> DeltaRunIter<'a> {
449
0
        DeltaRunIter::new(self.data.cursor(), self.count)
450
0
    }
451
452
0
    pub fn fetcher(&self) -> PackedDeltaFetcher<'a> {
453
0
        PackedDeltaFetcher::new(self.data.as_bytes(), self.count)
454
0
    }
455
456
861
    fn x_deltas(&self) -> DeltaRunIter<'a> {
457
861
        let count = self.count_or_compute() / 2;
458
861
        DeltaRunIter::new(self.data.cursor(), Some(count))
459
861
    }
460
461
861
    fn y_deltas(&self) -> DeltaRunIter<'a> {
462
861
        let count = self.count_or_compute();
463
861
        DeltaRunIter::new(self.data.cursor(), Some(count)).skip_fast(count / 2)
464
861
    }
465
}
466
467
/// Flag indicating that this run contains no data,
468
/// and that the deltas for this run are all zero.
469
const DELTAS_ARE_ZERO: u8 = 0x80;
470
/// Flag indicating the data type for delta values in the run.
471
const DELTAS_ARE_WORDS: u8 = 0x40;
472
/// Mask for the low 6 bits to provide the number of delta values in the run, minus one.
473
const DELTA_RUN_COUNT_MASK: u8 = 0x3F;
474
475
/// The type of values for a given delta run (influences the number of bytes per delta)
476
///
477
/// The variants are intentionally set to the byte size of the type to allow usage
478
/// as a multiplier when computing offsets.
479
#[derive(Clone, Copy, Debug, PartialEq)]
480
pub enum DeltaRunType {
481
    Zero = 0,
482
    I8 = 1,
483
    I16 = 2,
484
    I32 = 4,
485
}
486
487
impl DeltaRunType {
488
    /// The run type for a given control byte
489
26.4k
    pub fn new(control: u8) -> Self {
490
        // if the top two bits of the control byte (DELTAS_ARE_ZERO and DELTAS_ARE_WORDS) are both set,
491
        // then the following values are 32-bit.
492
        // <https://github.com/harfbuzz/boring-expansion-spec/blob/main/VARC.md#tuplevalues>
493
26.4k
        let are_zero = (control & DELTAS_ARE_ZERO) != 0;
494
26.4k
        let are_words = (control & DELTAS_ARE_WORDS) != 0;
495
26.4k
        match (are_zero, are_words) {
496
13.0k
            (false, false) => Self::I8,
497
1.71k
            (false, true) => Self::I16,
498
10.3k
            (true, false) => Self::Zero,
499
1.34k
            (true, true) => Self::I32,
500
        }
501
26.4k
    }
502
}
503
504
/// Implements the logic for iterating over the individual runs
505
#[derive(Clone, Debug)]
506
pub struct DeltaRunIter<'a> {
507
    limit: Option<usize>, // when None, consume all available data
508
    remaining_in_run: u8,
509
    value_type: DeltaRunType,
510
    cursor: Cursor<'a>,
511
}
512
513
/// A decoding helper that adds packed deltas directly to an output slice.
514
pub struct PackedDeltaFetcher<'a> {
515
    data: &'a [u8],
516
    pos: usize,
517
    end: usize,
518
    run_count: usize,
519
    value_type: DeltaRunType,
520
    remaining_total: Option<usize>,
521
}
522
523
impl<'a> PackedDeltaFetcher<'a> {
524
0
    fn new(data: &'a [u8], count: Option<usize>) -> Self {
525
0
        Self {
526
0
            data,
527
0
            pos: 0,
528
0
            end: data.len(),
529
0
            run_count: 0,
530
0
            value_type: DeltaRunType::I8,
531
0
            remaining_total: count,
532
0
        }
533
0
    }
534
535
    #[inline(always)]
536
0
    fn ensure_run(&mut self) -> Result<(), ReadError> {
537
0
        if self.run_count > 0 {
538
0
            return Ok(());
539
0
        }
540
0
        if self.pos >= self.end {
541
0
            return Err(ReadError::OutOfBounds);
542
0
        }
543
0
        let control = self.data[self.pos];
544
0
        self.pos += 1;
545
0
        self.run_count = (control & DELTA_RUN_COUNT_MASK) as usize + 1;
546
0
        self.value_type = DeltaRunType::new(control);
547
0
        let width = self.value_type as usize;
548
0
        let needed = self.run_count * width;
549
0
        if self.pos + needed > self.end {
550
0
            return Err(ReadError::OutOfBounds);
551
0
        }
552
0
        Ok(())
553
0
    }
554
555
0
    pub fn skip(&mut self, mut n: usize) -> Result<(), ReadError> {
556
0
        if let Some(remaining_total) = self.remaining_total {
557
0
            if n > remaining_total {
558
0
                return Err(ReadError::OutOfBounds);
559
0
            }
560
0
            self.remaining_total = Some(remaining_total - n);
561
0
        }
562
0
        while n > 0 {
563
0
            self.ensure_run()?;
564
0
            let take = n.min(self.run_count);
565
0
            let width = self.value_type as usize;
566
0
            self.pos += take * width;
567
0
            self.run_count -= take;
568
0
            n -= take;
569
        }
570
0
        Ok(())
571
0
    }
572
573
0
    pub fn add_to_f32_scaled(&mut self, out: &mut [f32], scale: f32) -> Result<(), ReadError> {
574
0
        self.add_to_scaled(out, scale, |delta| delta as f32)
575
0
    }
576
577
    /// Adds packed deltas without losing precision from 32-bit integer values.
578
0
    pub fn add_to_f64_scaled(&mut self, out: &mut [f64], scale: f64) -> Result<(), ReadError> {
579
0
        self.add_to_scaled(out, scale, |delta| delta as f64)
580
0
    }
581
582
0
    fn add_to_scaled<T>(
583
0
        &mut self,
584
0
        out: &mut [T],
585
0
        scale: T,
586
0
        convert: impl Fn(i32) -> T,
587
0
    ) -> Result<(), ReadError>
588
0
    where
589
0
        T: Copy + core::ops::AddAssign + core::ops::Mul<Output = T>,
590
    {
591
0
        let mut remaining = out.len();
592
0
        if let Some(remaining_total) = self.remaining_total {
593
0
            if remaining > remaining_total {
594
0
                return Err(ReadError::OutOfBounds);
595
0
            }
596
0
            self.remaining_total = Some(remaining_total - remaining);
597
0
        }
598
0
        let mut idx = 0usize;
599
0
        while remaining > 0 {
600
0
            self.ensure_run()?;
601
0
            let take = remaining.min(self.run_count);
602
0
            match self.value_type {
603
0
                DeltaRunType::Zero => {
604
0
                    // nothing to add
605
0
                    idx += take;
606
0
                }
607
                DeltaRunType::I8 => {
608
0
                    let bytes = &self.data[self.pos..self.pos + take];
609
0
                    for &b in bytes {
610
0
                        out[idx] += convert(b as i8 as i32) * scale;
611
0
                        idx += 1;
612
0
                    }
613
0
                    self.pos += take;
614
                }
615
                DeltaRunType::I16 => {
616
0
                    let bytes = &self.data[self.pos..self.pos + take * 2];
617
0
                    for chunk in bytes.chunks_exact(2) {
618
0
                        let delta = i16::from_be_bytes([chunk[0], chunk[1]]) as i32;
619
0
                        out[idx] += convert(delta) * scale;
620
0
                        idx += 1;
621
0
                    }
622
0
                    self.pos += take * 2;
623
                }
624
                DeltaRunType::I32 => {
625
0
                    let bytes = &self.data[self.pos..self.pos + take * 4];
626
0
                    for chunk in bytes.chunks_exact(4) {
627
0
                        let delta = i32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
628
0
                        out[idx] += convert(delta) * scale;
629
0
                        idx += 1;
630
0
                    }
631
0
                    self.pos += take * 4;
632
                }
633
            }
634
0
            self.run_count -= take;
635
0
            remaining -= take;
636
        }
637
0
        Ok(())
638
0
    }
Unexecuted instantiation: <read_fonts::tables::variations::PackedDeltaFetcher>::add_to_scaled::<f64, <read_fonts::tables::variations::PackedDeltaFetcher>::add_to_f64_scaled::{closure#0}>
Unexecuted instantiation: <read_fonts::tables::variations::PackedDeltaFetcher>::add_to_scaled::<f32, <read_fonts::tables::variations::PackedDeltaFetcher>::add_to_f32_scaled::{closure#0}>
639
}
640
641
/// Counts the number of deltas available in the given data, avoiding
642
/// excessive reads.
643
1.10k
fn count_all_deltas(data: FontData) -> usize {
644
1.10k
    let mut count = 0;
645
1.10k
    let mut offset = 0;
646
12.1k
    while let Ok(control) = data.read_at::<u8>(offset) {
647
11.0k
        let run_count = (control & DELTA_RUN_COUNT_MASK) as usize + 1;
648
11.0k
        count += run_count;
649
11.0k
        offset += run_count * DeltaRunType::new(control) as usize + 1;
650
11.0k
    }
651
1.10k
    count
652
1.10k
}
653
654
impl<'a> DeltaRunIter<'a> {
655
1.72k
    fn new(cursor: Cursor<'a>, limit: Option<usize>) -> Self {
656
1.72k
        DeltaRunIter {
657
1.72k
            limit,
658
1.72k
            remaining_in_run: 0,
659
1.72k
            value_type: DeltaRunType::I8,
660
1.72k
            cursor,
661
1.72k
        }
662
1.72k
    }
663
664
0
    pub(crate) fn end(mut self) -> Cursor<'a> {
665
0
        if let Some(limit) = self.limit {
666
0
            return self.skip_fast(limit).cursor;
667
0
        }
668
        // No limit: jump over runs without decoding values.
669
0
        if self.remaining_in_run != 0 {
670
0
            if self.value_type != DeltaRunType::Zero {
671
0
                self.cursor
672
0
                    .advance_by(self.remaining_in_run as usize * self.value_type as usize);
673
0
            }
674
0
            self.remaining_in_run = 0;
675
0
        }
676
0
        while self.read_next_control().is_some() {
677
0
            if self.value_type != DeltaRunType::Zero {
678
0
                self.cursor
679
0
                    .advance_by(self.remaining_in_run as usize * self.value_type as usize);
680
0
            }
681
0
            self.remaining_in_run = 0;
682
        }
683
0
        self.cursor
684
0
    }
685
686
    /// Skips `n` deltas without reading the actual delta values.
687
    #[inline(always)]
688
861
    pub fn skip_fast(mut self, n: usize) -> Self {
689
861
        let mut wanted = n;
690
861
        let mut remaining = self.remaining_in_run as usize;
691
861
        let mut value_type = self.value_type;
692
        loop {
693
4.78k
            if wanted > remaining {
694
                // Consume the rest of this run and move to the next.
695
4.09k
                self.cursor.advance_by(remaining * value_type as usize);
696
4.09k
                wanted -= remaining;
697
4.09k
                if self.read_next_control().is_none() {
698
165
                    self.limit = Some(0);
699
165
                    break;
700
3.92k
                }
701
3.92k
                remaining = self.remaining_in_run as usize;
702
3.92k
                value_type = self.value_type;
703
3.92k
                continue;
704
696
            }
705
696
            let consumed = wanted;
706
696
            self.remaining_in_run -= consumed as u8;
707
696
            self.cursor.advance_by(consumed * value_type as usize);
708
696
            if let Some(limit) = self.limit.as_mut() {
709
696
                *limit = limit.saturating_sub(n);
710
696
            }
711
696
            break;
712
        }
713
861
        self
714
861
    }
715
716
    #[inline(always)]
717
9.46k
    fn read_next_control(&mut self) -> Option<()> {
718
9.46k
        self.remaining_in_run = 0;
719
9.46k
        let control: u8 = self.cursor.read().ok()?;
720
9.16k
        self.value_type = DeltaRunType::new(control);
721
9.16k
        self.remaining_in_run = (control & DELTA_RUN_COUNT_MASK) + 1;
722
9.16k
        Some(())
723
9.46k
    }
724
}
725
726
impl Iterator for DeltaRunIter<'_> {
727
    type Item = i32;
728
729
    #[inline(always)]
730
147k
    fn next(&mut self) -> Option<Self::Item> {
731
147k
        if let Some(limit) = self.limit {
732
147k
            if limit == 0 {
733
187
                return None;
734
147k
            }
735
147k
            self.limit = Some(limit - 1);
736
0
        }
737
147k
        if self.remaining_in_run == 0 {
738
5.37k
            self.read_next_control()?;
739
141k
        }
740
146k
        self.remaining_in_run -= 1;
741
146k
        match self.value_type {
742
128k
            DeltaRunType::Zero => Some(0),
743
7.65k
            DeltaRunType::I8 => self.cursor.read::<i8>().ok().map(|v| v as i32),
744
6.92k
            DeltaRunType::I16 => self.cursor.read::<i16>().ok().map(|v| v as i32),
745
4.30k
            DeltaRunType::I32 => self.cursor.read::<i32>().ok(),
746
        }
747
147k
    }
748
}
749
750
/// A helper type for iterating over [`TupleVariationHeader`]s.
751
pub struct TupleVariationHeaderIter<'a> {
752
    data: FontData<'a>,
753
    n_headers: usize,
754
    current: usize,
755
    axis_count: u16,
756
}
757
758
impl<'a> TupleVariationHeaderIter<'a> {
759
2.51k
    pub(crate) fn new(data: FontData<'a>, n_headers: usize, axis_count: u16) -> Self {
760
2.51k
        Self {
761
2.51k
            data,
762
2.51k
            n_headers,
763
2.51k
            current: 0,
764
2.51k
            axis_count,
765
2.51k
        }
766
2.51k
    }
767
}
768
769
impl<'a> Iterator for TupleVariationHeaderIter<'a> {
770
    type Item = Result<TupleVariationHeader<'a>, ReadError>;
771
772
    #[inline(always)]
773
27.4k
    fn next(&mut self) -> Option<Self::Item> {
774
27.4k
        if self.current == self.n_headers {
775
140
            return None;
776
27.3k
        }
777
27.3k
        self.current += 1;
778
27.3k
        let next = TupleVariationHeader::read(self.data, self.axis_count);
779
780
27.3k
        let next_len = next
781
27.3k
            .as_ref()
782
27.3k
            .map(|table| table.byte_len(self.axis_count))
783
27.3k
            .unwrap_or(0);
784
27.3k
        self.data = self.data.split_off(next_len)?;
785
26.9k
        Some(next)
786
27.4k
    }
787
}
788
789
#[derive(Clone)]
790
pub struct TupleVariationData<'a, T> {
791
    pub(crate) axis_count: u16,
792
    pub(crate) shared_tuples: Option<ComputedArray<'a, Tuple<'a>>>,
793
    pub(crate) shared_point_numbers: Option<PackedPointNumbers<'a>>,
794
    pub(crate) tuple_count: TupleVariationCount,
795
    // the data for all the tuple variation headers
796
    pub(crate) header_data: FontData<'a>,
797
    // the data for all the tuple bodies
798
    pub(crate) serialized_data: FontData<'a>,
799
    pub(crate) _marker: std::marker::PhantomData<fn() -> T>,
800
}
801
802
impl<'a, T> TupleVariationData<'a, T>
803
where
804
    T: TupleDelta,
805
{
806
0
    pub fn tuples(&self) -> TupleVariationIter<'a, T> {
807
0
        TupleVariationIter {
808
0
            current: 0,
809
0
            parent: self.clone(),
810
0
            header_iter: TupleVariationHeaderIter::new(
811
0
                self.header_data,
812
0
                self.tuple_count.count() as usize,
813
0
                self.axis_count,
814
0
            ),
815
0
            serialized_data: self.serialized_data,
816
0
            _marker: std::marker::PhantomData,
817
0
        }
818
0
    }
819
820
    /// Returns an iterator over all of the pairs of (variation tuple, scalar)
821
    /// for this glyph that are active for the given set of normalized
822
    /// coordinates.
823
0
    pub fn active_tuples_at<'b>(
824
0
        &self,
825
0
        coords: &'b [F2Dot14],
826
0
    ) -> impl Iterator<Item = (TupleVariation<'a, T>, Fixed)> + 'b
827
0
    where
828
0
        'a: 'b,
829
    {
830
0
        self.active_tuples_at_with_scalars(coords, &[])
831
0
    }
832
833
    /// Returns an iterator over the tuples that apply at `coords`, reusing
834
    /// `scalars`.
835
    ///
836
    /// `scalars` holds one entry per shared tuple, from
837
    /// [`Gvar::compute_scalars`]. A tuple that names a shared peak and no
838
    /// range of its own has the same scalar everywhere, so it is read from
839
    /// there. A tuple with its own range, or one `scalars` does not reach, is
840
    /// computed here.
841
    ///
842
    /// [`Gvar::compute_scalars`]: crate::tables::gvar::Gvar::compute_scalars
843
2.51k
    pub fn active_tuples_at_with_scalars<'b>(
844
2.51k
        &self,
845
2.51k
        coords: &'b [F2Dot14],
846
2.51k
        scalars: &'b [Fixed],
847
2.51k
    ) -> impl Iterator<Item = (TupleVariation<'a, T>, Fixed)> + 'b
848
2.51k
    where
849
2.51k
        'a: 'b,
850
    {
851
2.51k
        ActiveTupleVariationIter {
852
2.51k
            coords,
853
2.51k
            scalars,
854
2.51k
            parent: self.clone(),
855
2.51k
            header_iter: TupleVariationHeaderIter::new(
856
2.51k
                self.header_data,
857
2.51k
                self.tuple_count.count() as usize,
858
2.51k
                self.axis_count,
859
2.51k
            ),
860
2.51k
            serialized_data: self.serialized_data,
861
2.51k
            data_offset: 0,
862
2.51k
            _marker: std::marker::PhantomData,
863
2.51k
        }
864
2.51k
    }
Unexecuted instantiation: <read_fonts::tables::variations::TupleVariationData<read_fonts::tables::cvar::CvtDelta>>::active_tuples_at_with_scalars
<read_fonts::tables::variations::TupleVariationData<read_fonts::tables::gvar::GlyphDelta>>::active_tuples_at_with_scalars
Line
Count
Source
843
2.51k
    pub fn active_tuples_at_with_scalars<'b>(
844
2.51k
        &self,
845
2.51k
        coords: &'b [F2Dot14],
846
2.51k
        scalars: &'b [Fixed],
847
2.51k
    ) -> impl Iterator<Item = (TupleVariation<'a, T>, Fixed)> + 'b
848
2.51k
    where
849
2.51k
        'a: 'b,
850
    {
851
2.51k
        ActiveTupleVariationIter {
852
2.51k
            coords,
853
2.51k
            scalars,
854
2.51k
            parent: self.clone(),
855
2.51k
            header_iter: TupleVariationHeaderIter::new(
856
2.51k
                self.header_data,
857
2.51k
                self.tuple_count.count() as usize,
858
2.51k
                self.axis_count,
859
2.51k
            ),
860
2.51k
            serialized_data: self.serialized_data,
861
2.51k
            data_offset: 0,
862
2.51k
            _marker: std::marker::PhantomData,
863
2.51k
        }
864
2.51k
    }
865
866
0
    pub(crate) fn tuple_count(&self) -> usize {
867
0
        self.tuple_count.count() as usize
868
0
    }
869
}
870
871
/// An iterator over the [`TupleVariation`]s for a specific glyph.
872
pub struct TupleVariationIter<'a, T> {
873
    current: usize,
874
    parent: TupleVariationData<'a, T>,
875
    header_iter: TupleVariationHeaderIter<'a>,
876
    serialized_data: FontData<'a>,
877
    _marker: std::marker::PhantomData<fn() -> T>,
878
}
879
880
impl<'a, T> TupleVariationIter<'a, T>
881
where
882
    T: TupleDelta,
883
{
884
    #[inline(always)]
885
0
    fn next_tuple(&mut self) -> Option<TupleVariation<'a, T>> {
886
0
        if self.parent.tuple_count() == self.current {
887
0
            return None;
888
0
        }
889
0
        self.current += 1;
890
891
        // FIXME: is it okay to discard an error here?
892
0
        let header = self.header_iter.next()?.ok()?;
893
0
        let data_len = header.variation_data_size() as usize;
894
0
        let var_data = self.serialized_data.take_up_to(data_len)?;
895
896
0
        Some(TupleVariation {
897
0
            axis_count: self.parent.axis_count,
898
0
            header,
899
0
            shared_tuples: self.parent.shared_tuples.clone(),
900
0
            serialized_data: var_data,
901
0
            shared_point_numbers: self.parent.shared_point_numbers.clone(),
902
0
            _marker: std::marker::PhantomData,
903
0
        })
904
0
    }
905
}
906
907
impl<'a, T> Iterator for TupleVariationIter<'a, T>
908
where
909
    T: TupleDelta,
910
{
911
    type Item = TupleVariation<'a, T>;
912
913
    #[inline(always)]
914
0
    fn next(&mut self) -> Option<Self::Item> {
915
0
        self.next_tuple()
916
0
    }
917
}
918
919
/// An iterator over the active [`TupleVariation`]s for a specific glyph
920
/// for a given set of coordinates.
921
struct ActiveTupleVariationIter<'a, 'b, T> {
922
    coords: &'b [F2Dot14],
923
    scalars: &'b [Fixed],
924
    parent: TupleVariationData<'a, T>,
925
    header_iter: TupleVariationHeaderIter<'a>,
926
    serialized_data: FontData<'a>,
927
    data_offset: usize,
928
    _marker: std::marker::PhantomData<fn() -> T>,
929
}
930
931
impl<'a, T> Iterator for ActiveTupleVariationIter<'a, '_, T>
932
where
933
    T: TupleDelta,
934
{
935
    type Item = (TupleVariation<'a, T>, Fixed);
936
937
    #[inline(always)]
938
3.69k
    fn next(&mut self) -> Option<Self::Item> {
939
        loop {
940
27.4k
            let header = self.header_iter.next()?.ok()?;
941
26.7k
            let data_len = header.variation_data_size() as usize;
942
26.7k
            let data_start = self.data_offset;
943
26.7k
            let data_end = data_start.checked_add(data_len)?;
944
26.7k
            self.data_offset = data_end;
945
26.7k
            if let Some(scalar) = compute_scalar(
946
26.7k
                &header,
947
26.7k
                self.parent.axis_count as usize,
948
26.7k
                &self.parent.shared_tuples,
949
26.7k
                self.coords,
950
26.7k
                self.scalars,
951
26.7k
            ) {
952
2.98k
                let var_data = self.serialized_data.slice(data_start..data_end)?;
953
2.08k
                return Some((
954
2.08k
                    TupleVariation {
955
2.08k
                        axis_count: self.parent.axis_count,
956
2.08k
                        header,
957
2.08k
                        shared_tuples: self.parent.shared_tuples.clone(),
958
2.08k
                        serialized_data: var_data,
959
2.08k
                        shared_point_numbers: self.parent.shared_point_numbers.clone(),
960
2.08k
                        _marker: std::marker::PhantomData,
961
2.08k
                    },
962
2.08k
                    scalar,
963
2.08k
                ));
964
23.7k
            }
965
        }
966
3.69k
    }
Unexecuted instantiation: <read_fonts::tables::variations::ActiveTupleVariationIter<read_fonts::tables::cvar::CvtDelta> as core::iter::traits::iterator::Iterator>::next
<read_fonts::tables::variations::ActiveTupleVariationIter<read_fonts::tables::gvar::GlyphDelta> as core::iter::traits::iterator::Iterator>::next
Line
Count
Source
938
3.69k
    fn next(&mut self) -> Option<Self::Item> {
939
        loop {
940
27.4k
            let header = self.header_iter.next()?.ok()?;
941
26.7k
            let data_len = header.variation_data_size() as usize;
942
26.7k
            let data_start = self.data_offset;
943
26.7k
            let data_end = data_start.checked_add(data_len)?;
944
26.7k
            self.data_offset = data_end;
945
26.7k
            if let Some(scalar) = compute_scalar(
946
26.7k
                &header,
947
26.7k
                self.parent.axis_count as usize,
948
26.7k
                &self.parent.shared_tuples,
949
26.7k
                self.coords,
950
26.7k
                self.scalars,
951
26.7k
            ) {
952
2.98k
                let var_data = self.serialized_data.slice(data_start..data_end)?;
953
2.08k
                return Some((
954
2.08k
                    TupleVariation {
955
2.08k
                        axis_count: self.parent.axis_count,
956
2.08k
                        header,
957
2.08k
                        shared_tuples: self.parent.shared_tuples.clone(),
958
2.08k
                        serialized_data: var_data,
959
2.08k
                        shared_point_numbers: self.parent.shared_point_numbers.clone(),
960
2.08k
                        _marker: std::marker::PhantomData,
961
2.08k
                    },
962
2.08k
                    scalar,
963
2.08k
                ));
964
23.7k
            }
965
        }
966
3.69k
    }
967
}
968
969
/// Marks a shared tuple scalar that was never computed.
970
///
971
/// A glyph names shared tuples by index and need not name them all, so a
972
/// slice of scalars can carry gaps. Variation store regions are dense and
973
/// need no such mark.
974
///
975
/// No computed scalar can equal this: a scalar is a product of ratios, each
976
/// held between zero and one.
977
pub const NOT_COMPUTED: Fixed = Fixed::MAX;
978
979
/// A single set of tuple variation data
980
#[derive(Clone)]
981
pub struct TupleVariation<'a, T> {
982
    axis_count: u16,
983
    header: TupleVariationHeader<'a>,
984
    shared_tuples: Option<ComputedArray<'a, Tuple<'a>>>,
985
    serialized_data: FontData<'a>,
986
    shared_point_numbers: Option<PackedPointNumbers<'a>>,
987
    _marker: std::marker::PhantomData<fn() -> T>,
988
}
989
990
impl<'a, T> TupleVariation<'a, T>
991
where
992
    T: TupleDelta,
993
{
994
    /// Returns true if this tuple provides deltas for all points in a glyph.
995
1.36k
    pub fn has_deltas_for_all_points(&self) -> bool {
996
1.36k
        if self.header.tuple_index().private_point_numbers() {
997
890
            PackedPointNumbers {
998
890
                data: self.serialized_data,
999
890
            }
1000
890
            .count()
1001
890
                == 0
1002
470
        } else if let Some(shared) = &self.shared_point_numbers {
1003
335
            shared.count() == 0
1004
        } else {
1005
135
            false
1006
        }
1007
1.36k
    }
1008
1009
0
    pub fn point_numbers(&self) -> PackedPointNumbersIter<'a> {
1010
0
        let (point_numbers, _) = self.point_numbers_and_packed_deltas();
1011
0
        point_numbers.iter()
1012
0
    }
1013
1014
    /// Returns the 'peak' tuple for this variation
1015
0
    pub fn peak(&self) -> Tuple<'a> {
1016
0
        self.header
1017
0
            .tuple_index()
1018
0
            .tuple_records_index()
1019
0
            .and_then(|idx| self.shared_tuples.as_ref()?.get(idx as usize).ok())
1020
0
            .or_else(|| self.header.peak_tuple())
1021
0
            .unwrap_or_default()
1022
0
    }
1023
1024
0
    pub fn intermediate_start(&self) -> Option<Tuple<'a>> {
1025
0
        self.header.intermediate_start_tuple()
1026
0
    }
1027
1028
0
    pub fn intermediate_end(&self) -> Option<Tuple<'a>> {
1029
0
        self.header.intermediate_end_tuple()
1030
0
    }
1031
1032
    /// Compute the fixed point scalar for this tuple at the given location in
1033
    /// variation space.
1034
    ///
1035
    /// The `coords` slice must be of lesser or equal length to the number of
1036
    /// axes. If it is less, missing (trailing) axes will be assumed to have
1037
    /// zero values.
1038
    ///
1039
    /// Returns `None` if this tuple is not applicable at the provided
1040
    /// coordinates (e.g. if the resulting scalar is zero).
1041
0
    pub fn compute_scalar(&self, coords: &[F2Dot14]) -> Option<Fixed> {
1042
0
        compute_scalar(
1043
0
            &self.header,
1044
0
            self.axis_count as usize,
1045
0
            &self.shared_tuples,
1046
0
            coords,
1047
0
            &[],
1048
        )
1049
0
    }
1050
1051
    /// Compute the floating point scalar for this tuple at the given location
1052
    /// in variation space.
1053
    ///
1054
    /// The `coords` slice must be of lesser or equal length to the number of
1055
    /// axes. If it is less, missing (trailing) axes will be assumed to have
1056
    /// zero values.
1057
    ///
1058
    /// Returns `None` if this tuple is not applicable at the provided
1059
    /// coordinates (e.g. if the resulting scalar is zero).
1060
0
    pub fn compute_scalar_f32(&self, coords: &[F2Dot14]) -> Option<f32> {
1061
0
        let mut scalar = 1.0;
1062
0
        let peak = self.peak();
1063
0
        let inter_start = self.header.intermediate_start_tuple();
1064
0
        let inter_end = self.header.intermediate_end_tuple();
1065
0
        if peak.len() != self.axis_count as usize {
1066
0
            return None;
1067
0
        }
1068
0
        for i in 0..self.axis_count {
1069
0
            let i = i as usize;
1070
0
            let coord = coords.get(i).copied().unwrap_or_default().to_bits() as i32;
1071
0
            let peak = peak.get(i).unwrap_or_default().to_bits() as i32;
1072
0
            if peak == 0 || peak == coord {
1073
0
                continue;
1074
0
            }
1075
0
            if coord == 0 {
1076
0
                return None;
1077
0
            }
1078
0
            if let (Some(inter_start), Some(inter_end)) = (&inter_start, &inter_end) {
1079
0
                let start = inter_start.get(i).unwrap_or_default().to_bits() as i32;
1080
0
                let end = inter_end.get(i).unwrap_or_default().to_bits() as i32;
1081
0
                if start > peak || peak > end || (start < 0 && end > 0 && peak != 0) {
1082
0
                    continue;
1083
0
                }
1084
0
                if coord < start || coord > end {
1085
0
                    return None;
1086
0
                }
1087
0
                if coord < peak {
1088
0
                    if peak != start {
1089
0
                        scalar *= (coord - start) as f32 / (peak - start) as f32;
1090
0
                    }
1091
0
                } else if peak != end {
1092
0
                    scalar *= (end - coord) as f32 / (end - peak) as f32;
1093
0
                }
1094
            } else {
1095
0
                if coord < peak.min(0) || coord > peak.max(0) {
1096
0
                    return None;
1097
0
                }
1098
0
                scalar *= coord as f32 / peak as f32;
1099
            }
1100
        }
1101
0
        Some(scalar)
1102
0
    }
1103
1104
    /// Iterate over the deltas for this tuple.
1105
    ///
1106
    /// This does not account for scaling. Returns only explicitly encoded
1107
    /// deltas, e.g. an omission by IUP will not be present.
1108
861
    pub fn deltas(&self) -> TupleDeltaIter<'a, T> {
1109
861
        let (point_numbers, packed_deltas) = self.point_numbers_and_packed_deltas();
1110
861
        let count = point_numbers.count() as usize;
1111
861
        let packed_deltas = if count == 0 {
1112
553
            PackedDeltas::consume_all(packed_deltas)
1113
        } else {
1114
308
            PackedDeltas::new(packed_deltas, if T::is_point() { count * 2 } else { count })
1115
        };
1116
861
        TupleDeltaIter::new(&point_numbers, packed_deltas)
1117
861
    }
Unexecuted instantiation: <read_fonts::tables::variations::TupleVariation<read_fonts::tables::cvar::CvtDelta>>::deltas
<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::deltas
Line
Count
Source
1108
861
    pub fn deltas(&self) -> TupleDeltaIter<'a, T> {
1109
861
        let (point_numbers, packed_deltas) = self.point_numbers_and_packed_deltas();
1110
861
        let count = point_numbers.count() as usize;
1111
861
        let packed_deltas = if count == 0 {
1112
553
            PackedDeltas::consume_all(packed_deltas)
1113
        } else {
1114
308
            PackedDeltas::new(packed_deltas, if T::is_point() { count * 2 } else { count })
1115
        };
1116
861
        TupleDeltaIter::new(&point_numbers, packed_deltas)
1117
861
    }
1118
1119
2.08k
    fn point_numbers_and_packed_deltas(&self) -> (PackedPointNumbers<'a>, FontData<'a>) {
1120
2.08k
        if self.header.tuple_index().private_point_numbers() {
1121
1.25k
            PackedPointNumbers::split_off_front(self.serialized_data)
1122
        } else {
1123
834
            (
1124
834
                self.shared_point_numbers.clone().unwrap_or_default(),
1125
834
                self.serialized_data,
1126
834
            )
1127
        }
1128
2.08k
    }
Unexecuted instantiation: <read_fonts::tables::variations::TupleVariation<read_fonts::tables::cvar::CvtDelta>>::point_numbers_and_packed_deltas
<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::point_numbers_and_packed_deltas
Line
Count
Source
1119
2.08k
    fn point_numbers_and_packed_deltas(&self) -> (PackedPointNumbers<'a>, FontData<'a>) {
1120
2.08k
        if self.header.tuple_index().private_point_numbers() {
1121
1.25k
            PackedPointNumbers::split_off_front(self.serialized_data)
1122
        } else {
1123
834
            (
1124
834
                self.shared_point_numbers.clone().unwrap_or_default(),
1125
834
                self.serialized_data,
1126
834
            )
1127
        }
1128
2.08k
    }
1129
}
1130
1131
impl TupleVariation<'_, GlyphDelta> {
1132
    /// Reads the set of deltas from this tuple variation.
1133
    ///
1134
    /// This is significantly faster than using the [`Self::deltas`]
1135
    /// method but requires preallocated memory to store deltas and
1136
    /// flags.
1137
    ///
1138
    /// This method should only be used when the tuple variation is dense,
1139
    /// that is, [`Self::has_deltas_for_all_points`] returns true.
1140
    ///
1141
    /// The size of `deltas` must be the same as the target value set to
1142
    /// which the variation is applied. For simple outlines, this is
1143
    /// `num_points + 4` and for composites it is `num_components + 4`
1144
    /// (where the `+ 4` is to accommodate phantom points).
1145
    ///
1146
    /// The `deltas` slice will not be zeroed before accumulation and each
1147
    /// delta will be multiplied by the given `scalar`.
1148
370
    pub fn accumulate_dense_deltas<D: PointCoord>(
1149
370
        &self,
1150
370
        deltas: &mut [Point<D>],
1151
370
        scalar: Fixed,
1152
370
    ) -> Result<(), ReadError> {
1153
370
        let (_, packed_deltas) = self.point_numbers_and_packed_deltas();
1154
370
        let mut cursor = packed_deltas.cursor();
1155
370
        if scalar == Fixed::ONE {
1156
            // scalar of 1.0 is common so avoid the costly conversions and
1157
            // multiplications per coord
1158
549
            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1159
549
                delta.x += D::from_i32(new_delta);
1160
549
            })?;
Unexecuted instantiation: <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas::<font_types::fixed::Fixed>::{closure#0}
<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas::<f32>::{closure#0}
Line
Count
Source
1158
549
            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1159
549
                delta.x += D::from_i32(new_delta);
1160
549
            })?;
1161
281
            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1162
281
                delta.y += D::from_i32(new_delta);
1163
281
            })?;
Unexecuted instantiation: <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas::<font_types::fixed::Fixed>::{closure#1}
<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas::<f32>::{closure#1}
Line
Count
Source
1161
281
            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1162
281
                delta.y += D::from_i32(new_delta);
1163
281
            })?;
1164
        } else {
1165
69
            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1166
61
                delta.x += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1167
61
            })?;
Unexecuted instantiation: <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas::<font_types::fixed::Fixed>::{closure#2}
<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas::<f32>::{closure#2}
Line
Count
Source
1165
61
            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1166
61
                delta.x += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1167
61
            })?;
1168
30
            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1169
30
                delta.y += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1170
30
            })?;
Unexecuted instantiation: <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas::<font_types::fixed::Fixed>::{closure#3}
<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas::<f32>::{closure#3}
Line
Count
Source
1168
30
            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1169
30
                delta.y += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1170
30
            })?;
1171
        }
1172
44
        Ok(())
1173
370
    }
Unexecuted instantiation: <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas::<font_types::fixed::Fixed>
<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas::<f32>
Line
Count
Source
1148
370
    pub fn accumulate_dense_deltas<D: PointCoord>(
1149
370
        &self,
1150
370
        deltas: &mut [Point<D>],
1151
370
        scalar: Fixed,
1152
370
    ) -> Result<(), ReadError> {
1153
370
        let (_, packed_deltas) = self.point_numbers_and_packed_deltas();
1154
370
        let mut cursor = packed_deltas.cursor();
1155
370
        if scalar == Fixed::ONE {
1156
            // scalar of 1.0 is common so avoid the costly conversions and
1157
            // multiplications per coord
1158
301
            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1159
                delta.x += D::from_i32(new_delta);
1160
201
            })?;
1161
100
            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1162
                delta.y += D::from_i32(new_delta);
1163
61
            })?;
1164
        } else {
1165
69
            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1166
                delta.x += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1167
60
            })?;
1168
9
            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1169
                delta.y += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1170
4
            })?;
1171
        }
1172
44
        Ok(())
1173
370
    }
1174
1175
    /// Reads the set of deltas from this tuple variation.
1176
    ///
1177
    /// This is significantly faster than using the [`Self::deltas`]
1178
    /// method but requires preallocated memory to store deltas and
1179
    /// flags.
1180
    ///
1181
    /// This method should only be used when the tuple variation is sparse,
1182
    /// that is, [`Self::has_deltas_for_all_points`] returns false.
1183
    ///
1184
    /// The size of `deltas` must be the same as the target value set to
1185
    /// which the variation is applied. For simple outlines, this is
1186
    /// `num_points + 4` and for composites it is `num_components + 4`
1187
    /// (where the `+ 4` is to accommodate phantom points).
1188
    ///
1189
    /// The `deltas` and `flags` slices must be the same size. Modifications
1190
    /// to `deltas` will be sparse and for each entry that is modified, the
1191
    /// [PointMarker::HAS_DELTA] marker will be set for the corresponding
1192
    /// entry in the `flags` slice.
1193
    ///
1194
    /// The `deltas` slice will not be zeroed before accumulation and each
1195
    /// delta will be multiplied by the given `scalar`.
1196
858
    pub fn accumulate_sparse_deltas<D: PointCoord>(
1197
858
        &self,
1198
858
        deltas: &mut [Point<D>],
1199
858
        flags: &mut [PointFlags],
1200
858
        scalar: Fixed,
1201
858
    ) -> Result<(), ReadError> {
1202
858
        let (point_numbers, packed_deltas) = self.point_numbers_and_packed_deltas();
1203
858
        let mut cursor = packed_deltas.cursor();
1204
858
        let count = point_numbers.count() as usize;
1205
858
        if scalar == Fixed::ONE {
1206
            // scalar of 1.0 is common so avoid the costly conversions and
1207
            // multiplications per coord
1208
16.5k
            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1209
16.5k
                if let Some((delta, flag)) = deltas.get_mut(ix).zip(flags.get_mut(ix)) {
1210
2.16k
                    delta.x += D::from_i32(new_delta);
1211
2.16k
                    flag.set_marker(PointMarker::HAS_DELTA);
1212
14.3k
                }
1213
16.5k
            })?;
Unexecuted instantiation: <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas::<font_types::fixed::Fixed>::{closure#0}
<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas::<f32>::{closure#0}
Line
Count
Source
1208
16.5k
            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1209
16.5k
                if let Some((delta, flag)) = deltas.get_mut(ix).zip(flags.get_mut(ix)) {
1210
2.16k
                    delta.x += D::from_i32(new_delta);
1211
2.16k
                    flag.set_marker(PointMarker::HAS_DELTA);
1212
14.3k
                }
1213
16.5k
            })?;
1214
5.21k
            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1215
5.21k
                if let Some(delta) = deltas.get_mut(ix) {
1216
640
                    delta.y += D::from_i32(new_delta);
1217
4.57k
                }
1218
5.21k
            })?;
Unexecuted instantiation: <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas::<font_types::fixed::Fixed>::{closure#1}
<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas::<f32>::{closure#1}
Line
Count
Source
1214
5.21k
            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1215
5.21k
                if let Some(delta) = deltas.get_mut(ix) {
1216
640
                    delta.y += D::from_i32(new_delta);
1217
4.57k
                }
1218
5.21k
            })?;
1219
        } else {
1220
1.40k
            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1221
1.40k
                if let Some((delta, flag)) = deltas.get_mut(ix).zip(flags.get_mut(ix)) {
1222
48
                    delta.x += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1223
48
                    flag.set_marker(PointMarker::HAS_DELTA);
1224
1.35k
                }
1225
1.40k
            })?;
Unexecuted instantiation: <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas::<font_types::fixed::Fixed>::{closure#2}
<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas::<f32>::{closure#2}
Line
Count
Source
1220
1.40k
            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1221
1.40k
                if let Some((delta, flag)) = deltas.get_mut(ix).zip(flags.get_mut(ix)) {
1222
48
                    delta.x += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1223
48
                    flag.set_marker(PointMarker::HAS_DELTA);
1224
1.35k
                }
1225
1.40k
            })?;
1226
434
            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1227
434
                if let Some(delta) = deltas.get_mut(ix) {
1228
26
                    delta.y += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1229
408
                }
1230
434
            })?;
Unexecuted instantiation: <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas::<font_types::fixed::Fixed>::{closure#3}
<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas::<f32>::{closure#3}
Line
Count
Source
1226
434
            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1227
434
                if let Some(delta) = deltas.get_mut(ix) {
1228
26
                    delta.y += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1229
408
                }
1230
434
            })?;
1231
        }
1232
273
        Ok(())
1233
858
    }
Unexecuted instantiation: <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas::<font_types::fixed::Fixed>
<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas::<f32>
Line
Count
Source
1196
858
    pub fn accumulate_sparse_deltas<D: PointCoord>(
1197
858
        &self,
1198
858
        deltas: &mut [Point<D>],
1199
858
        flags: &mut [PointFlags],
1200
858
        scalar: Fixed,
1201
858
    ) -> Result<(), ReadError> {
1202
858
        let (point_numbers, packed_deltas) = self.point_numbers_and_packed_deltas();
1203
858
        let mut cursor = packed_deltas.cursor();
1204
858
        let count = point_numbers.count() as usize;
1205
858
        if scalar == Fixed::ONE {
1206
            // scalar of 1.0 is common so avoid the costly conversions and
1207
            // multiplications per coord
1208
664
            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1209
                if let Some((delta, flag)) = deltas.get_mut(ix).zip(flags.get_mut(ix)) {
1210
                    delta.x += D::from_i32(new_delta);
1211
                    flag.set_marker(PointMarker::HAS_DELTA);
1212
                }
1213
249
            })?;
1214
415
            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1215
                if let Some(delta) = deltas.get_mut(ix) {
1216
                    delta.y += D::from_i32(new_delta);
1217
                }
1218
224
            })?;
1219
        } else {
1220
194
            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1221
                if let Some((delta, flag)) = deltas.get_mut(ix).zip(flags.get_mut(ix)) {
1222
                    delta.x += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1223
                    flag.set_marker(PointMarker::HAS_DELTA);
1224
                }
1225
98
            })?;
1226
96
            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1227
                if let Some(delta) = deltas.get_mut(ix) {
1228
                    delta.y += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1229
                }
1230
14
            })?;
1231
        }
1232
273
        Ok(())
1233
858
    }
1234
}
1235
1236
/// This is basically a manually applied loop unswitching optimization
1237
/// for reading deltas. It reads each typed run into a slice for processing
1238
/// instead of handling each delta individually with all the necessary
1239
/// branching that implies.
1240
479
fn read_dense_deltas<T>(
1241
479
    cursor: &mut Cursor,
1242
479
    deltas: &mut [T],
1243
479
    mut f: impl FnMut(&mut T, i32),
1244
479
) -> Result<(), ReadError> {
1245
479
    let count = deltas.len();
1246
479
    let mut cur = 0;
1247
1.27k
    while cur < count {
1248
1.12k
        let control: u8 = cursor.read()?;
1249
1.02k
        let value_type = DeltaRunType::new(control);
1250
1.02k
        let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1251
1.02k
        let dest = deltas
1252
1.02k
            .get_mut(cur..cur + run_count)
1253
1.02k
            .ok_or(ReadError::OutOfBounds)?;
1254
827
        match value_type {
1255
26
            DeltaRunType::Zero => {}
1256
            DeltaRunType::I8 => {
1257
751
                let packed_deltas = cursor.read_array::<i8>(run_count)?;
1258
856
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1259
856
                    f(delta, *new_delta as i32);
1260
856
                }
1261
            }
1262
            DeltaRunType::I16 => {
1263
42
                let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1264
46
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1265
46
                    f(delta, new_delta.get() as i32);
1266
46
                }
1267
            }
1268
            DeltaRunType::I32 => {
1269
8
                let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1270
19
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1271
19
                    f(delta, new_delta.get());
1272
19
                }
1273
            }
1274
        }
1275
798
        cur += run_count;
1276
    }
1277
153
    Ok(())
1278
479
}
Unexecuted instantiation: read_fonts::tables::variations::read_dense_deltas::<font_types::point::Point<font_types::fixed::Fixed>, <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas<font_types::fixed::Fixed>::{closure#0}>
Unexecuted instantiation: read_fonts::tables::variations::read_dense_deltas::<font_types::point::Point<font_types::fixed::Fixed>, <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas<font_types::fixed::Fixed>::{closure#2}>
Unexecuted instantiation: read_fonts::tables::variations::read_dense_deltas::<font_types::point::Point<font_types::fixed::Fixed>, <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas<font_types::fixed::Fixed>::{closure#3}>
Unexecuted instantiation: read_fonts::tables::variations::read_dense_deltas::<font_types::point::Point<font_types::fixed::Fixed>, <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas<font_types::fixed::Fixed>::{closure#1}>
read_fonts::tables::variations::read_dense_deltas::<font_types::point::Point<f32>, <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas<f32>::{closure#0}>
Line
Count
Source
1240
301
fn read_dense_deltas<T>(
1241
301
    cursor: &mut Cursor,
1242
301
    deltas: &mut [T],
1243
301
    mut f: impl FnMut(&mut T, i32),
1244
301
) -> Result<(), ReadError> {
1245
301
    let count = deltas.len();
1246
301
    let mut cur = 0;
1247
763
    while cur < count {
1248
663
        let control: u8 = cursor.read()?;
1249
588
        let value_type = DeltaRunType::new(control);
1250
588
        let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1251
588
        let dest = deltas
1252
588
            .get_mut(cur..cur + run_count)
1253
588
            .ok_or(ReadError::OutOfBounds)?;
1254
485
        match value_type {
1255
20
            DeltaRunType::Zero => {}
1256
            DeltaRunType::I8 => {
1257
438
                let packed_deltas = cursor.read_array::<i8>(run_count)?;
1258
512
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1259
512
                    f(delta, *new_delta as i32);
1260
512
                }
1261
            }
1262
            DeltaRunType::I16 => {
1263
24
                let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1264
28
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1265
28
                    f(delta, new_delta.get() as i32);
1266
28
                }
1267
            }
1268
            DeltaRunType::I32 => {
1269
3
                let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1270
9
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1271
9
                    f(delta, new_delta.get());
1272
9
                }
1273
            }
1274
        }
1275
462
        cur += run_count;
1276
    }
1277
100
    Ok(())
1278
301
}
read_fonts::tables::variations::read_dense_deltas::<font_types::point::Point<f32>, <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas<f32>::{closure#2}>
Line
Count
Source
1240
69
fn read_dense_deltas<T>(
1241
69
    cursor: &mut Cursor,
1242
69
    deltas: &mut [T],
1243
69
    mut f: impl FnMut(&mut T, i32),
1244
69
) -> Result<(), ReadError> {
1245
69
    let count = deltas.len();
1246
69
    let mut cur = 0;
1247
122
    while cur < count {
1248
113
        let control: u8 = cursor.read()?;
1249
86
        let value_type = DeltaRunType::new(control);
1250
86
        let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1251
86
        let dest = deltas
1252
86
            .get_mut(cur..cur + run_count)
1253
86
            .ok_or(ReadError::OutOfBounds)?;
1254
59
        match value_type {
1255
0
            DeltaRunType::Zero => {}
1256
            DeltaRunType::I8 => {
1257
59
                let packed_deltas = cursor.read_array::<i8>(run_count)?;
1258
61
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1259
61
                    f(delta, *new_delta as i32);
1260
61
                }
1261
            }
1262
            DeltaRunType::I16 => {
1263
0
                let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1264
0
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1265
0
                    f(delta, new_delta.get() as i32);
1266
0
                }
1267
            }
1268
            DeltaRunType::I32 => {
1269
0
                let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1270
0
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1271
0
                    f(delta, new_delta.get());
1272
0
                }
1273
            }
1274
        }
1275
53
        cur += run_count;
1276
    }
1277
9
    Ok(())
1278
69
}
read_fonts::tables::variations::read_dense_deltas::<font_types::point::Point<f32>, <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas<f32>::{closure#3}>
Line
Count
Source
1240
9
fn read_dense_deltas<T>(
1241
9
    cursor: &mut Cursor,
1242
9
    deltas: &mut [T],
1243
9
    mut f: impl FnMut(&mut T, i32),
1244
9
) -> Result<(), ReadError> {
1245
9
    let count = deltas.len();
1246
9
    let mut cur = 0;
1247
33
    while cur < count {
1248
28
        let control: u8 = cursor.read()?;
1249
28
        let value_type = DeltaRunType::new(control);
1250
28
        let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1251
28
        let dest = deltas
1252
28
            .get_mut(cur..cur + run_count)
1253
28
            .ok_or(ReadError::OutOfBounds)?;
1254
24
        match value_type {
1255
0
            DeltaRunType::Zero => {}
1256
            DeltaRunType::I8 => {
1257
24
                let packed_deltas = cursor.read_array::<i8>(run_count)?;
1258
30
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1259
30
                    f(delta, *new_delta as i32);
1260
30
                }
1261
            }
1262
            DeltaRunType::I16 => {
1263
0
                let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1264
0
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1265
0
                    f(delta, new_delta.get() as i32);
1266
0
                }
1267
            }
1268
            DeltaRunType::I32 => {
1269
0
                let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1270
0
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1271
0
                    f(delta, new_delta.get());
1272
0
                }
1273
            }
1274
        }
1275
24
        cur += run_count;
1276
    }
1277
5
    Ok(())
1278
9
}
read_fonts::tables::variations::read_dense_deltas::<font_types::point::Point<f32>, <read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_dense_deltas<f32>::{closure#1}>
Line
Count
Source
1240
100
fn read_dense_deltas<T>(
1241
100
    cursor: &mut Cursor,
1242
100
    deltas: &mut [T],
1243
100
    mut f: impl FnMut(&mut T, i32),
1244
100
) -> Result<(), ReadError> {
1245
100
    let count = deltas.len();
1246
100
    let mut cur = 0;
1247
359
    while cur < count {
1248
320
        let control: u8 = cursor.read()?;
1249
320
        let value_type = DeltaRunType::new(control);
1250
320
        let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1251
320
        let dest = deltas
1252
320
            .get_mut(cur..cur + run_count)
1253
320
            .ok_or(ReadError::OutOfBounds)?;
1254
259
        match value_type {
1255
6
            DeltaRunType::Zero => {}
1256
            DeltaRunType::I8 => {
1257
230
                let packed_deltas = cursor.read_array::<i8>(run_count)?;
1258
253
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1259
253
                    f(delta, *new_delta as i32);
1260
253
                }
1261
            }
1262
            DeltaRunType::I16 => {
1263
18
                let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1264
18
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1265
18
                    f(delta, new_delta.get() as i32);
1266
18
                }
1267
            }
1268
            DeltaRunType::I32 => {
1269
5
                let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1270
10
                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1271
10
                    f(delta, new_delta.get());
1272
10
                }
1273
            }
1274
        }
1275
259
        cur += run_count;
1276
    }
1277
39
    Ok(())
1278
100
}
1279
1280
/// See [read_dense_deltas] docs.
1281
1.36k
fn read_sparse_deltas(
1282
1.36k
    cursor: &mut Cursor,
1283
1.36k
    point_numbers: &PackedPointNumbers,
1284
1.36k
    count: usize,
1285
1.36k
    mut f: impl FnMut(usize, i32),
1286
1.36k
) -> Result<(), ReadError> {
1287
1.36k
    let mut cur = 0;
1288
23.5k
    let mut points_iter = point_numbers.iter().map(|ix| ix as usize);
Unexecuted instantiation: read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<font_types::fixed::Fixed>::{closure#0}>::{closure#0}
Unexecuted instantiation: read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<font_types::fixed::Fixed>::{closure#2}>::{closure#0}
Unexecuted instantiation: read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<font_types::fixed::Fixed>::{closure#3}>::{closure#0}
Unexecuted instantiation: read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<font_types::fixed::Fixed>::{closure#1}>::{closure#0}
read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<f32>::{closure#0}>::{closure#0}
Line
Count
Source
1288
16.5k
    let mut points_iter = point_numbers.iter().map(|ix| ix as usize);
read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<f32>::{closure#2}>::{closure#0}
Line
Count
Source
1288
1.40k
    let mut points_iter = point_numbers.iter().map(|ix| ix as usize);
read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<f32>::{closure#3}>::{closure#0}
Line
Count
Source
1288
434
    let mut points_iter = point_numbers.iter().map(|ix| ix as usize);
read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<f32>::{closure#1}>::{closure#0}
Line
Count
Source
1288
5.21k
    let mut points_iter = point_numbers.iter().map(|ix| ix as usize);
1289
6.11k
    while cur < count {
1290
5.33k
        let control: u8 = cursor.read()?;
1291
5.23k
        let value_type = DeltaRunType::new(control);
1292
5.23k
        let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1293
5.23k
        match value_type {
1294
            DeltaRunType::Zero => {
1295
899
                for _ in 0..run_count {
1296
8.76k
                    let point_ix = points_iter.next().ok_or(ReadError::OutOfBounds)?;
1297
8.61k
                    f(point_ix, 0);
1298
                }
1299
            }
1300
            DeltaRunType::I8 => {
1301
3.60k
                let packed_deltas = cursor.read_array::<i8>(run_count)?;
1302
10.8k
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1303
10.8k
                    f(point_ix, *new_delta as i32);
1304
10.8k
                }
1305
            }
1306
            DeltaRunType::I16 => {
1307
454
                let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1308
2.78k
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1309
2.78k
                    f(point_ix, new_delta.get() as i32);
1310
2.78k
                }
1311
            }
1312
            DeltaRunType::I32 => {
1313
279
                let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1314
1.32k
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1315
1.32k
                    f(point_ix, new_delta.get());
1316
1.32k
                }
1317
            }
1318
        }
1319
4.74k
        cur += run_count;
1320
    }
1321
784
    Ok(())
1322
1.36k
}
Unexecuted instantiation: read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<font_types::fixed::Fixed>::{closure#0}>
Unexecuted instantiation: read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<font_types::fixed::Fixed>::{closure#2}>
Unexecuted instantiation: read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<font_types::fixed::Fixed>::{closure#3}>
Unexecuted instantiation: read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<font_types::fixed::Fixed>::{closure#1}>
read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<f32>::{closure#0}>
Line
Count
Source
1281
664
fn read_sparse_deltas(
1282
664
    cursor: &mut Cursor,
1283
664
    point_numbers: &PackedPointNumbers,
1284
664
    count: usize,
1285
664
    mut f: impl FnMut(usize, i32),
1286
664
) -> Result<(), ReadError> {
1287
664
    let mut cur = 0;
1288
664
    let mut points_iter = point_numbers.iter().map(|ix| ix as usize);
1289
4.09k
    while cur < count {
1290
3.67k
        let control: u8 = cursor.read()?;
1291
3.63k
        let value_type = DeltaRunType::new(control);
1292
3.63k
        let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1293
3.63k
        match value_type {
1294
            DeltaRunType::Zero => {
1295
696
                for _ in 0..run_count {
1296
5.66k
                    let point_ix = points_iter.next().ok_or(ReadError::OutOfBounds)?;
1297
5.60k
                    f(point_ix, 0);
1298
                }
1299
            }
1300
            DeltaRunType::I8 => {
1301
2.55k
                let packed_deltas = cursor.read_array::<i8>(run_count)?;
1302
8.32k
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1303
8.32k
                    f(point_ix, *new_delta as i32);
1304
8.32k
                }
1305
            }
1306
            DeltaRunType::I16 => {
1307
251
                let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1308
2.01k
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1309
2.01k
                    f(point_ix, new_delta.get() as i32);
1310
2.01k
                }
1311
            }
1312
            DeltaRunType::I32 => {
1313
128
                let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1314
561
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1315
561
                    f(point_ix, new_delta.get());
1316
561
                }
1317
            }
1318
        }
1319
3.43k
        cur += run_count;
1320
    }
1321
415
    Ok(())
1322
664
}
read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<f32>::{closure#2}>
Line
Count
Source
1281
194
fn read_sparse_deltas(
1282
194
    cursor: &mut Cursor,
1283
194
    point_numbers: &PackedPointNumbers,
1284
194
    count: usize,
1285
194
    mut f: impl FnMut(usize, i32),
1286
194
) -> Result<(), ReadError> {
1287
194
    let mut cur = 0;
1288
194
    let mut points_iter = point_numbers.iter().map(|ix| ix as usize);
1289
323
    while cur < count {
1290
227
        let control: u8 = cursor.read()?;
1291
190
        let value_type = DeltaRunType::new(control);
1292
190
        let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1293
190
        match value_type {
1294
            DeltaRunType::Zero => {
1295
25
                for _ in 0..run_count {
1296
290
                    let point_ix = points_iter.next().ok_or(ReadError::OutOfBounds)?;
1297
267
                    f(point_ix, 0);
1298
                }
1299
            }
1300
            DeltaRunType::I8 => {
1301
106
                let packed_deltas = cursor.read_array::<i8>(run_count)?;
1302
603
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1303
603
                    f(point_ix, *new_delta as i32);
1304
603
                }
1305
            }
1306
            DeltaRunType::I16 => {
1307
22
                let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1308
118
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1309
118
                    f(point_ix, new_delta.get() as i32);
1310
118
                }
1311
            }
1312
            DeltaRunType::I32 => {
1313
37
                let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1314
418
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1315
418
                    f(point_ix, new_delta.get());
1316
418
                }
1317
            }
1318
        }
1319
129
        cur += run_count;
1320
    }
1321
96
    Ok(())
1322
194
}
read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<f32>::{closure#3}>
Line
Count
Source
1281
96
fn read_sparse_deltas(
1282
96
    cursor: &mut Cursor,
1283
96
    point_numbers: &PackedPointNumbers,
1284
96
    count: usize,
1285
96
    mut f: impl FnMut(usize, i32),
1286
96
) -> Result<(), ReadError> {
1287
96
    let mut cur = 0;
1288
96
    let mut points_iter = point_numbers.iter().map(|ix| ix as usize);
1289
174
    while cur < count {
1290
92
        let control: u8 = cursor.read()?;
1291
92
        let value_type = DeltaRunType::new(control);
1292
92
        let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1293
92
        match value_type {
1294
            DeltaRunType::Zero => {
1295
4
                for _ in 0..run_count {
1296
130
                    let point_ix = points_iter.next().ok_or(ReadError::OutOfBounds)?;
1297
126
                    f(point_ix, 0);
1298
                }
1299
            }
1300
            DeltaRunType::I8 => {
1301
65
                let packed_deltas = cursor.read_array::<i8>(run_count)?;
1302
246
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1303
246
                    f(point_ix, *new_delta as i32);
1304
246
                }
1305
            }
1306
            DeltaRunType::I16 => {
1307
18
                let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1308
60
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1309
60
                    f(point_ix, new_delta.get() as i32);
1310
60
                }
1311
            }
1312
            DeltaRunType::I32 => {
1313
5
                let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1314
2
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1315
2
                    f(point_ix, new_delta.get());
1316
2
                }
1317
            }
1318
        }
1319
78
        cur += run_count;
1320
    }
1321
82
    Ok(())
1322
96
}
read_fonts::tables::variations::read_sparse_deltas::<<read_fonts::tables::variations::TupleVariation<read_fonts::tables::gvar::GlyphDelta>>::accumulate_sparse_deltas<f32>::{closure#1}>
Line
Count
Source
1281
415
fn read_sparse_deltas(
1282
415
    cursor: &mut Cursor,
1283
415
    point_numbers: &PackedPointNumbers,
1284
415
    count: usize,
1285
415
    mut f: impl FnMut(usize, i32),
1286
415
) -> Result<(), ReadError> {
1287
415
    let mut cur = 0;
1288
415
    let mut points_iter = point_numbers.iter().map(|ix| ix as usize);
1289
1.52k
    while cur < count {
1290
1.33k
        let control: u8 = cursor.read()?;
1291
1.31k
        let value_type = DeltaRunType::new(control);
1292
1.31k
        let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1293
1.31k
        match value_type {
1294
            DeltaRunType::Zero => {
1295
174
                for _ in 0..run_count {
1296
2.68k
                    let point_ix = points_iter.next().ok_or(ReadError::OutOfBounds)?;
1297
2.62k
                    f(point_ix, 0);
1298
                }
1299
            }
1300
            DeltaRunType::I8 => {
1301
873
                let packed_deltas = cursor.read_array::<i8>(run_count)?;
1302
1.65k
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1303
1.65k
                    f(point_ix, *new_delta as i32);
1304
1.65k
                }
1305
            }
1306
            DeltaRunType::I16 => {
1307
163
                let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1308
597
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1309
597
                    f(point_ix, new_delta.get() as i32);
1310
597
                }
1311
            }
1312
            DeltaRunType::I32 => {
1313
109
                let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1314
341
                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1315
341
                    f(point_ix, new_delta.get());
1316
341
                }
1317
            }
1318
        }
1319
1.11k
        cur += run_count;
1320
    }
1321
191
    Ok(())
1322
415
}
1323
1324
/// Compute the fixed point scalar for this tuple at the given location in
1325
/// variation space.
1326
///
1327
/// The `coords` slice must be of lesser or equal length to the number of
1328
/// axes. If it is less, missing (trailing) axes will be assumed to have
1329
/// zero values.
1330
///
1331
/// Returns `None` if this tuple is not applicable at the provided
1332
/// coordinates (e.g. if the resulting scalar is zero).
1333
#[inline(always)]
1334
26.7k
fn compute_scalar<'a>(
1335
26.7k
    header: &TupleVariationHeader,
1336
26.7k
    axis_count: usize,
1337
26.7k
    shared_tuples: &Option<ComputedArray<'a, Tuple<'a>>>,
1338
26.7k
    coords: &[F2Dot14],
1339
26.7k
    scalars: &[Fixed],
1340
26.7k
) -> Option<Fixed> {
1341
26.7k
    let tuple_idx = header.tuple_index();
1342
26.7k
    let intermediate = header.intermediate_tuples();
1343
26.7k
    let peak = if let Some(shared_index) = tuple_idx.tuple_records_index() {
1344
        // A shared peak with no range of its own has the same scalar
1345
        // wherever it is named, so a cached value applies.
1346
20.6k
        if intermediate.is_none() {
1347
16.7k
            match scalars.get(shared_index as usize) {
1348
3.67k
                Some(scalar) if *scalar != NOT_COMPUTED => {
1349
3.67k
                    return (*scalar != Fixed::ZERO).then_some(*scalar);
1350
                }
1351
13.0k
                _ => {}
1352
            }
1353
3.86k
        }
1354
16.9k
        shared_tuples.as_ref()?.get(shared_index as usize).ok()?
1355
    } else {
1356
6.13k
        header.peak_tuple()?
1357
    };
1358
6.17k
    if peak.len() != axis_count {
1359
0
        return None;
1360
6.17k
    }
1361
6.17k
    scalar_for(&peak, intermediate, coords)
1362
26.7k
}
1363
1364
/// Computes the scalar for a peak at `coords`, interpolating over the tuple's
1365
/// range if it states one.
1366
///
1367
/// `None` where the tuple does not apply, which a scalar of zero also
1368
/// expresses.
1369
10.0k
pub(crate) fn scalar_for(
1370
10.0k
    peak: &Tuple,
1371
10.0k
    intermediate: Option<(Tuple, Tuple)>,
1372
10.0k
    coords: &[F2Dot14],
1373
10.0k
) -> Option<Fixed> {
1374
10.0k
    let mut scalar = Fixed::ONE;
1375
21.5k
    for (i, peak) in peak
1376
10.0k
        .values
1377
10.0k
        .iter()
1378
10.0k
        .enumerate()
1379
26.3k
        .filter(|(_, peak)| peak.get() != F2Dot14::ZERO)
1380
    {
1381
21.5k
        let coord = coords.get(i).copied().unwrap_or_default();
1382
21.5k
        if coord == F2Dot14::ZERO {
1383
3.60k
            return None;
1384
17.9k
        }
1385
17.9k
        let peak = peak.get();
1386
17.9k
        if peak == coord {
1387
38
            continue;
1388
17.8k
        }
1389
17.8k
        if let Some((inter_start, inter_end)) = &intermediate {
1390
13.1k
            let start = inter_start.get(i).unwrap_or_default();
1391
13.1k
            let end = inter_end.get(i).unwrap_or_default();
1392
            // A region that does not enclose its own peak, or that straddles
1393
            // the default, is invalid and contributes a factor of one. This
1394
            // mirrors the OpenType algorithm and the sibling scalar
1395
            // computations (`compute_scalar_f32`, `VariationRegion::compute_scalar`);
1396
            // without it a malformed region interpolates where it should be
1397
            // skipped.
1398
13.1k
            if start > peak || peak > end || (start < F2Dot14::ZERO && end > F2Dot14::ZERO) {
1399
11.5k
                continue;
1400
1.61k
            }
1401
1.61k
            if coord <= start || coord >= end {
1402
512
                return None;
1403
1.10k
            }
1404
1.10k
            let coord = coord.to_fixed();
1405
1.10k
            let peak = peak.to_fixed();
1406
1.10k
            if coord < peak {
1407
456
                let start = start.to_fixed();
1408
456
                scalar = scalar.mul_div(coord - start, peak - start);
1409
644
            } else {
1410
644
                let end = end.to_fixed();
1411
644
                scalar = scalar.mul_div(end - coord, end - peak);
1412
644
            }
1413
        } else {
1414
4.70k
            if coord < peak.min(F2Dot14::ZERO) || coord > peak.max(F2Dot14::ZERO) {
1415
2.48k
                return None;
1416
2.21k
            }
1417
2.21k
            let coord = coord.to_fixed();
1418
2.21k
            let peak = peak.to_fixed();
1419
2.21k
            scalar = scalar.mul_div(coord, peak);
1420
        }
1421
    }
1422
3.40k
    (scalar != Fixed::ZERO).then_some(scalar)
1423
10.0k
}
1424
1425
#[derive(Clone, Debug)]
1426
enum TupleDeltaValues<'a> {
1427
    // Point deltas have separate runs for x and y coordinates.
1428
    Points(DeltaRunIter<'a>, DeltaRunIter<'a>),
1429
    Scalars(DeltaRunIter<'a>),
1430
}
1431
1432
/// An iterator over the deltas for a glyph.
1433
#[derive(Clone, Debug)]
1434
pub struct TupleDeltaIter<'a, T> {
1435
    pub cur: usize,
1436
    // if None all points get deltas, if Some specifies subset of points that do
1437
    points: Option<PackedPointNumbersIter<'a>>,
1438
    next_point: usize,
1439
    values: TupleDeltaValues<'a>,
1440
    _marker: std::marker::PhantomData<fn() -> T>,
1441
}
1442
1443
impl<'a, T> TupleDeltaIter<'a, T>
1444
where
1445
    T: TupleDelta,
1446
{
1447
861
    fn new(points: &PackedPointNumbers<'a>, deltas: PackedDeltas<'a>) -> TupleDeltaIter<'a, T> {
1448
861
        let mut points = points.iter();
1449
861
        let next_point = points.next();
1450
861
        let values = if T::is_point() {
1451
861
            TupleDeltaValues::Points(deltas.x_deltas(), deltas.y_deltas())
1452
        } else {
1453
0
            TupleDeltaValues::Scalars(deltas.iter())
1454
        };
1455
        TupleDeltaIter {
1456
            cur: 0,
1457
861
            points: next_point.map(|_| points),
1458
861
            next_point: next_point.unwrap_or_default() as usize,
1459
861
            values,
1460
861
            _marker: std::marker::PhantomData,
1461
        }
1462
861
    }
Unexecuted instantiation: <read_fonts::tables::variations::TupleDeltaIter<read_fonts::tables::cvar::CvtDelta>>::new
<read_fonts::tables::variations::TupleDeltaIter<read_fonts::tables::gvar::GlyphDelta>>::new
Line
Count
Source
1447
861
    fn new(points: &PackedPointNumbers<'a>, deltas: PackedDeltas<'a>) -> TupleDeltaIter<'a, T> {
1448
861
        let mut points = points.iter();
1449
861
        let next_point = points.next();
1450
861
        let values = if T::is_point() {
1451
861
            TupleDeltaValues::Points(deltas.x_deltas(), deltas.y_deltas())
1452
        } else {
1453
0
            TupleDeltaValues::Scalars(deltas.iter())
1454
        };
1455
        TupleDeltaIter {
1456
            cur: 0,
1457
861
            points: next_point.map(|_| points),
1458
861
            next_point: next_point.unwrap_or_default() as usize,
1459
861
            values,
1460
861
            _marker: std::marker::PhantomData,
1461
        }
1462
861
    }
1463
}
1464
1465
/// Trait for deltas that are computed in a tuple variation store.
1466
pub trait TupleDelta: Sized + Copy + 'static {
1467
    /// Returns true if the delta is a point and requires reading two values
1468
    /// from the packed delta stream.
1469
    fn is_point() -> bool;
1470
1471
    /// Creates a new delta for the given position and coordinates. If
1472
    /// the delta is not a point, the y value will always be zero.
1473
    fn new(position: u16, x: i32, y: i32) -> Self;
1474
}
1475
1476
impl<T> Iterator for TupleDeltaIter<'_, T>
1477
where
1478
    T: TupleDelta,
1479
{
1480
    type Item = T;
1481
1482
73.9k
    fn next(&mut self) -> Option<Self::Item> {
1483
73.0k
        let (position, dx, dy) = loop {
1484
3.38M
            let position = if let Some(points) = &mut self.points {
1485
                // if we have points then result is sparse; only some points have deltas
1486
3.38M
                if self.cur > self.next_point {
1487
74.0k
                    self.next_point = points.next()? as usize;
1488
3.31M
                }
1489
3.38M
                self.next_point
1490
            } else {
1491
                // no points, every point has a delta. Just take the next one.
1492
81
                self.cur
1493
            };
1494
3.38M
            if position == self.cur {
1495
73.8k
                let (dx, dy) = match &mut self.values {
1496
73.8k
                    TupleDeltaValues::Points(x, y) => (x.next()?, y.next()?),
1497
0
                    TupleDeltaValues::Scalars(scalars) => (scalars.next()?, 0),
1498
                };
1499
73.0k
                break (position, dx, dy);
1500
3.31M
            }
1501
3.31M
            self.cur += 1;
1502
        };
1503
73.0k
        self.cur += 1;
1504
73.0k
        Some(T::new(position as u16, dx, dy))
1505
73.9k
    }
Unexecuted instantiation: <read_fonts::tables::variations::TupleDeltaIter<read_fonts::tables::cvar::CvtDelta> as core::iter::traits::iterator::Iterator>::next
<read_fonts::tables::variations::TupleDeltaIter<read_fonts::tables::gvar::GlyphDelta> as core::iter::traits::iterator::Iterator>::next
Line
Count
Source
1482
73.9k
    fn next(&mut self) -> Option<Self::Item> {
1483
73.0k
        let (position, dx, dy) = loop {
1484
3.38M
            let position = if let Some(points) = &mut self.points {
1485
                // if we have points then result is sparse; only some points have deltas
1486
3.38M
                if self.cur > self.next_point {
1487
74.0k
                    self.next_point = points.next()? as usize;
1488
3.31M
                }
1489
3.38M
                self.next_point
1490
            } else {
1491
                // no points, every point has a delta. Just take the next one.
1492
81
                self.cur
1493
            };
1494
3.38M
            if position == self.cur {
1495
73.8k
                let (dx, dy) = match &mut self.values {
1496
73.8k
                    TupleDeltaValues::Points(x, y) => (x.next()?, y.next()?),
1497
0
                    TupleDeltaValues::Scalars(scalars) => (scalars.next()?, 0),
1498
                };
1499
73.0k
                break (position, dx, dy);
1500
3.31M
            }
1501
3.31M
            self.cur += 1;
1502
        };
1503
73.0k
        self.cur += 1;
1504
73.0k
        Some(T::new(position as u16, dx, dy))
1505
73.9k
    }
1506
}
1507
1508
impl EntryFormat {
1509
1.84k
    pub fn entry_size(self) -> u8 {
1510
1.84k
        ((self.bits() & Self::MAP_ENTRY_SIZE_MASK.bits()) >> 4) + 1
1511
1.84k
    }
1512
1513
260
    pub fn bit_count(self) -> u8 {
1514
260
        (self.bits() & Self::INNER_INDEX_BIT_COUNT_MASK.bits()) + 1
1515
260
    }
1516
1517
    // called from codegen
1518
1.01k
    pub(crate) fn map_size(self, map_count: impl Into<u32>) -> usize {
1519
1.01k
        self.entry_size() as usize * map_count.into() as usize
1520
1.01k
    }
<read_fonts::tables::variations::EntryFormat>::map_size::<u32>
Line
Count
Source
1518
340
    pub(crate) fn map_size(self, map_count: impl Into<u32>) -> usize {
1519
340
        self.entry_size() as usize * map_count.into() as usize
1520
340
    }
<read_fonts::tables::variations::EntryFormat>::map_size::<u16>
Line
Count
Source
1518
673
    pub(crate) fn map_size(self, map_count: impl Into<u32>) -> usize {
1519
673
        self.entry_size() as usize * map_count.into() as usize
1520
673
    }
1521
}
1522
1523
impl DeltaSetIndexMap<'_> {
1524
    /// Returns the delta set index for the specified value.
1525
1.01k
    pub fn get(&self, index: u32) -> Result<DeltaSetIndex, ReadError> {
1526
1.01k
        let (entry_format, map_count, data) = match self {
1527
673
            Self::Format0(fmt) => (fmt.entry_format(), fmt.map_count() as u32, fmt.map_data()),
1528
340
            Self::Format1(fmt) => (fmt.entry_format(), fmt.map_count(), fmt.map_data()),
1529
        };
1530
1.01k
        if map_count == 0 {
1531
180
            return Ok(DeltaSetIndex {
1532
180
                outer: (index >> 16) as u16,
1533
180
                inner: index as u16,
1534
180
            });
1535
833
        }
1536
833
        let entry_size = entry_format.entry_size();
1537
833
        let data = FontData::new(data);
1538
        // "if an index into the mapping array is used that is greater than or equal to
1539
        // mapCount, then the last logical entry of the mapping array is used."
1540
        // https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats
1541
        // #associating-target-items-to-variation-data
1542
833
        let index = index.min(map_count.saturating_sub(1));
1543
833
        let offset = index as usize * entry_size as usize;
1544
833
        let entry = match entry_size {
1545
175
            1 => data.read_at::<u8>(offset)? as u32,
1546
110
            2 => data.read_at::<u16>(offset)? as u32,
1547
401
            3 => data.read_at::<Uint24>(offset)?.into(),
1548
147
            4 => data.read_at::<u32>(offset)?,
1549
            _ => {
1550
0
                return Err(ReadError::MalformedData(
1551
0
                    "invalid entry size in DeltaSetIndexMap",
1552
0
                ))
1553
            }
1554
        };
1555
260
        let bit_count = entry_format.bit_count();
1556
260
        Ok(DeltaSetIndex {
1557
260
            outer: (entry >> bit_count) as u16,
1558
260
            inner: (entry & ((1 << bit_count) - 1)) as u16,
1559
260
        })
1560
1.01k
    }
1561
}
1562
1563
impl ItemVariationStore<'_> {
1564
    /// Computes the delta value for the specified index and set of
1565
    /// normalized variation coordinates.
1566
    ///
1567
    /// Each region's scalar is computed in 16.16 and multiplied by its raw
1568
    /// delta, and the products are summed exactly -- 48.16 holds the largest
1569
    /// possible sum with room to spare. Use [`F48Dot16::to_i32`] for the
1570
    /// classic integer delta, or apply the value unrounded to targets that
1571
    /// take fractional deltas.
1572
22
    pub fn compute_delta(&self, index: DeltaSetIndex, coords: &[F2Dot14]) -> Option<F48Dot16> {
1573
22
        self.compute_delta_with_scalars(index, coords, &[])
1574
22
    }
1575
1576
    /// Computes the delta for `index` at `coords`, reusing `scalars`.
1577
    ///
1578
    /// `scalars` holds one entry per variation region, from
1579
    /// [`compute_scalars`](Self::compute_scalars). It may be empty or cover
1580
    /// only some of them; the rest are computed here.
1581
1.09k
    pub fn compute_delta_with_scalars(
1582
1.09k
        &self,
1583
1.09k
        index: DeltaSetIndex,
1584
1.09k
        coords: &[F2Dot14],
1585
1.09k
        scalars: &[Fixed],
1586
1.09k
    ) -> Option<F48Dot16> {
1587
1.09k
        if coords.is_empty() || index == DeltaSetIndex::NO_VARIATION_INDEX {
1588
3
            return Some(F48Dot16::ZERO);
1589
1.08k
        }
1590
1.08k
        let data = match self.item_variation_data().get(index.outer as usize) {
1591
1.06k
            Some(data) => data.ok()?,
1592
22
            None => return Some(F48Dot16::ZERO),
1593
        };
1594
97
        let region_indices = data.region_indexes();
1595
        // Read only when a scalar has to be computed. A run that finds all
1596
        // of them in `scalars` never touches the region list.
1597
97
        let mut regions = None;
1598
        // Compute deltas with 64-bit precision.
1599
        // See <https://gitlab.freedesktop.org/freetype/freetype/-/blob/7ab541a2/src/truetype/ttgxvar.c#L1094>
1600
97
        let mut accum = F48Dot16::ZERO;
1601
        // The deltas and the region indices are parallel arrays sized by the
1602
        // same header field, so they are walked together.
1603
97
        for (region_index, region_delta) in region_indices.iter().zip(data.delta_set(index.inner)) {
1604
0
            let region_index = region_index.get() as usize;
1605
0
            let scalar = match scalars.get(region_index) {
1606
0
                Some(scalar) => *scalar,
1607
                None => {
1608
0
                    let regions = match &regions {
1609
0
                        Some(regions) => regions,
1610
                        None => {
1611
0
                            regions.insert(self.variation_region_list().ok()?.variation_regions())
1612
                        }
1613
                    };
1614
0
                    let region = regions.get(region_index).ok()?;
1615
                    // A zero delta cannot contribute at any location. Still
1616
                    // resolve its region so malformed indices fail as before.
1617
0
                    if region_delta == 0 {
1618
0
                        continue;
1619
0
                    }
1620
0
                    region.compute_scalar(coords)
1621
                }
1622
            };
1623
            // The sum cannot overflow, even for hostile data: a scalar is a
1624
            // product of ratios that the range guards keep at most one, so
1625
            // each term is under 2^47, and at most 2^16 - 1 regions bounds
1626
            // the total below 2^63.
1627
0
            accum += scalar.mul_i32(region_delta);
1628
        }
1629
97
        Some(accum)
1630
1.09k
    }
1631
1632
    /// Computes the scalar for each variation region at `coords`, in store
1633
    /// order, and returns how many were written.
1634
    ///
1635
    /// A region that does not apply at `coords` is written as zero, which is
1636
    /// the value it contributes.
1637
    ///
1638
    /// `out` may be shorter than the store has regions, and an unreadable
1639
    /// store writes nothing.
1640
    /// [`compute_delta_with_scalars`](Self::compute_delta_with_scalars)
1641
    /// computes whatever is missing.
1642
    ///
1643
    /// Pass back only the entries this wrote. Regions are dense, so the
1644
    /// length of the slice is what identifies them.
1645
65
    pub fn compute_scalars(&self, coords: &[F2Dot14], out: &mut [Fixed]) -> usize {
1646
65
        let Ok(list) = self.variation_region_list() else {
1647
31
            return 0;
1648
        };
1649
34
        let regions = list.variation_regions();
1650
34
        let count = out.len().min(regions.len());
1651
34
        for (i, out) in out[..count].iter_mut().enumerate() {
1652
            // An unreadable region ends the run. Entries already written
1653
            // stay valid; the caller computes the rest.
1654
12
            let Ok(region) = regions.get(i) else {
1655
0
                return i;
1656
            };
1657
12
            *out = region.compute_scalar(coords);
1658
        }
1659
34
        count
1660
65
    }
1661
}
1662
1663
impl<'a> VariationRegion<'a> {
1664
    /// Computes a scalar value for this region and the specified
1665
    /// normalized variation coordinates.
1666
12
    pub fn compute_scalar(&self, coords: &[F2Dot14]) -> Fixed {
1667
        const ZERO: Fixed = Fixed::ZERO;
1668
12
        let mut scalar = Fixed::ONE;
1669
20
        for (i, peak, axis_coords) in self.active_region_axes() {
1670
            // A coordinate pinned to the peak contributes a factor of one,
1671
            // whatever the rest of the axis says: if the axis is invalid or
1672
            // the peak sits at an edge, the outcome is `continue` on every
1673
            // path below. Checking it first, in raw 2.14, skips the start
1674
            // and end reads and their conversions for the common case of an
1675
            // instance sitting on a region's corner.
1676
20
            let raw_coord = coords.get(i).copied().unwrap_or_default();
1677
20
            if raw_coord == peak {
1678
0
                continue;
1679
20
            }
1680
20
            let peak = peak.to_fixed();
1681
20
            let start = axis_coords.start_coord.get().to_fixed();
1682
20
            let end = axis_coords.end_coord.get().to_fixed();
1683
20
            if start > peak || peak > end || start < ZERO && end > ZERO {
1684
12
                continue;
1685
8
            }
1686
8
            let coord = raw_coord.to_fixed();
1687
8
            if coord < start || coord > end {
1688
5
                return ZERO;
1689
3
            } else if coord < peak {
1690
2
                scalar = scalar.mul_div(coord - start, peak - start);
1691
2
            } else {
1692
1
                scalar = scalar.mul_div(end - coord, end - peak);
1693
1
            }
1694
        }
1695
7
        scalar
1696
12
    }
1697
1698
12
    fn active_region_axes(
1699
12
        &self,
1700
12
    ) -> impl Iterator<Item = (usize, F2Dot14, &'a RegionAxisCoordinates)> {
1701
12
        self.region_axes()
1702
12
            .iter()
1703
12
            .enumerate()
1704
22
            .filter_map(|(i, axis_coords)| {
1705
22
                let peak = axis_coords.peak_coord();
1706
22
                if peak != F2Dot14::ZERO {
1707
20
                    Some((i, peak, axis_coords))
1708
                } else {
1709
2
                    None
1710
                }
1711
22
            })
1712
12
    }
1713
}
1714
1715
impl<'a> ItemVariationData<'a> {
1716
    /// Returns an iterator over the per-region delta values for the specified
1717
    /// inner index.
1718
97
    pub fn delta_set(&self, inner_index: u16) -> impl Iterator<Item = i32> + 'a + Clone {
1719
97
        let word_delta_count = self.word_delta_count();
1720
97
        let region_count = self.region_index_count();
1721
97
        let bytes_per_row = Self::delta_row_len(word_delta_count, region_count);
1722
97
        let long_words = word_delta_count & 0x8000 != 0;
1723
97
        let word_delta_count = word_delta_count & 0x7FFF;
1724
1725
97
        let offset = bytes_per_row * inner_index as usize;
1726
97
        ItemDeltas {
1727
97
            bytes: self.delta_sets().get(offset..).unwrap_or_default().iter(),
1728
97
            word_delta_count,
1729
97
            long_words,
1730
97
            len: region_count,
1731
97
            pos: 0,
1732
97
        }
1733
97
    }
1734
1735
0
    pub fn get_delta_row_len(&self) -> usize {
1736
0
        let word_delta_count = self.word_delta_count();
1737
0
        let region_count = self.region_index_count();
1738
0
        Self::delta_row_len(word_delta_count, region_count)
1739
0
    }
1740
1741
    /// the length of one delta set
1742
194
    pub fn delta_row_len(word_delta_count: u16, region_index_count: u16) -> usize {
1743
194
        let region_count = region_index_count as usize;
1744
194
        let long_words = word_delta_count & 0x8000 != 0;
1745
194
        let (word_size, small_size) = if long_words { (4, 2) } else { (2, 1) };
1746
194
        let long_delta_count = (word_delta_count & 0x7FFF) as usize;
1747
194
        let short_delta_count = region_count.saturating_sub(long_delta_count);
1748
194
        long_delta_count * word_size + short_delta_count * small_size
1749
194
    }
1750
1751
    // called from generated code: compute the length in bytes of the delta_sets data
1752
97
    pub fn delta_sets_len(
1753
97
        item_count: u16,
1754
97
        word_delta_count: u16,
1755
97
        region_index_count: u16,
1756
97
    ) -> usize {
1757
97
        let bytes_per_row = Self::delta_row_len(word_delta_count, region_index_count);
1758
97
        bytes_per_row * item_count as usize
1759
97
    }
1760
}
1761
1762
#[derive(Clone)]
1763
struct ItemDeltas<'a> {
1764
    bytes: core::slice::Iter<'a, u8>,
1765
    word_delta_count: u16,
1766
    long_words: bool,
1767
    len: u16,
1768
    pos: u16,
1769
}
1770
1771
impl Iterator for ItemDeltas<'_> {
1772
    type Item = i32;
1773
1774
48
    fn next(&mut self) -> Option<Self::Item> {
1775
48
        if self.pos >= self.len {
1776
0
            return None;
1777
48
        }
1778
48
        let pos = self.pos;
1779
48
        self.pos += 1;
1780
48
        let mut byte = || self.bytes.next().copied();
1781
48
        let value = match (pos >= self.word_delta_count, self.long_words) {
1782
22
            (true, true) | (false, false) => i16::from_be_bytes([byte()?, byte()?]) as i32,
1783
26
            (true, false) => byte()? as i8 as i32,
1784
0
            (false, true) => i32::from_be_bytes([byte()?, byte()?, byte()?, byte()?]),
1785
        };
1786
0
        Some(value)
1787
48
    }
1788
}
1789
1790
/// The delta for a glyph's advance, reusing `scalars`.
1791
///
1792
/// Keeps every bit the variation store computed. Rounding it to a whole
1793
/// design unit is left to a caller, and implementations differ on how.
1794
3.03k
pub(crate) fn advance_delta_with_scalars(
1795
3.03k
    dsim: Option<Result<DeltaSetIndexMap, ReadError>>,
1796
3.03k
    ivs: Result<ItemVariationStore, ReadError>,
1797
3.03k
    glyph_id: GlyphId,
1798
3.03k
    coords: &[F2Dot14],
1799
3.03k
    scalars: &[Fixed],
1800
3.03k
) -> Option<F48Dot16> {
1801
3.03k
    if coords.is_empty() {
1802
0
        return Some(F48Dot16::ZERO);
1803
3.03k
    }
1804
3.03k
    let gid = glyph_id.to_u32();
1805
2.46k
    let ix = match dsim {
1806
1.01k
        Some(Ok(dsim)) => dsim.get(gid).ok()?,
1807
        // Implicit mappings use outer index zero; an oversized glyph ID
1808
        // cannot address an inner row and must not wrap to a different glyph.
1809
2.02k
        _ if gid > u16::MAX as u32 => return Some(F48Dot16::ZERO),
1810
2.02k
        _ => DeltaSetIndex {
1811
2.02k
            outer: 0,
1812
2.02k
            inner: gid as _,
1813
2.02k
        },
1814
    };
1815
2.46k
    ivs.ok()?.compute_delta_with_scalars(ix, coords, scalars)
1816
3.03k
}
1817
1818
/// The delta for an item, reusing `scalars`.
1819
///
1820
/// As [`advance_delta_with_scalars`], but for mappings that require an index
1821
/// map instead of falling back to the glyph id.
1822
0
pub(crate) fn item_delta_with_scalars(
1823
0
    dsim: Option<Result<DeltaSetIndexMap, ReadError>>,
1824
0
    ivs: Result<ItemVariationStore, ReadError>,
1825
0
    glyph_id: GlyphId,
1826
0
    coords: &[F2Dot14],
1827
0
    scalars: &[Fixed],
1828
0
) -> Option<F48Dot16> {
1829
0
    if coords.is_empty() {
1830
0
        return Some(F48Dot16::ZERO);
1831
0
    }
1832
0
    let gid = glyph_id.to_u32();
1833
0
    let ix = match dsim {
1834
0
        Some(Ok(dsim)) => dsim.get(gid).ok()?,
1835
0
        _ => return None,
1836
    };
1837
0
    ivs.ok()?.compute_delta_with_scalars(ix, coords, scalars)
1838
0
}
1839
1840
#[cfg(test)]
1841
mod tests {
1842
    use font_test_data::bebuffer::BeBuffer;
1843
1844
    use super::*;
1845
    use crate::{FontRef, TableProvider};
1846
1847
    #[test]
1848
    fn zero_deltas_still_validate_their_regions() {
1849
        let store_bytes = |indices: [u16; 2]| {
1850
            BeBuffer::new()
1851
                .push(1u16) // ItemVariationStore format
1852
                .push(12u32) // region list offset
1853
                .push(1u16) // variation data count
1854
                .push(28u32) // variation data offset
1855
                .push(1u16) // axis count
1856
                .push(2u16) // region count
1857
                .extend([F2Dot14::ZERO, F2Dot14::ONE, F2Dot14::ONE])
1858
                .extend([F2Dot14::NEG_ONE, F2Dot14::NEG_ONE, F2Dot14::ZERO])
1859
                .push(2u16) // item count
1860
                .push(2u16) // word delta count
1861
                .push(2u16) // region index count
1862
                .extend(indices)
1863
                .extend([0i16, 120, -40, 0])
1864
        };
1865
        let bytes = store_bytes([0, 1]);
1866
        let store = ItemVariationStore::read(FontData::new(&bytes)).unwrap();
1867
        for coord in [-1.0, -0.25, 0.0, 0.25, 1.0] {
1868
            let coords = [F2Dot14::from_f32(coord)];
1869
            let mut scalars = [Fixed::ZERO; 2];
1870
            assert_eq!(store.compute_scalars(&coords, &mut scalars), 2);
1871
            for (inner, expected) in [120.0 * (-coord).max(0.0), -40.0 * coord.max(0.0)]
1872
                .into_iter()
1873
                .enumerate()
1874
            {
1875
                let index = DeltaSetIndex {
1876
                    outer: 0,
1877
                    inner: inner as u16,
1878
                };
1879
                let expected = Some(F48Dot16::from_f64(expected as f64));
1880
                assert_eq!(store.compute_delta(index, &coords), expected);
1881
                for count in 0..=2 {
1882
                    assert_eq!(
1883
                        store.compute_delta_with_scalars(index, &coords, &scalars[..count]),
1884
                        expected
1885
                    );
1886
                }
1887
            }
1888
        }
1889
        // Both the leading and trailing zero must reject an invalid region.
1890
        for (indices, inner) in [([2, 1], 0), ([0, 2], 1)] {
1891
            let bytes = store_bytes(indices);
1892
            let store = ItemVariationStore::read(FontData::new(&bytes)).unwrap();
1893
            assert_eq!(
1894
                store.compute_delta(DeltaSetIndex { outer: 0, inner }, &[F2Dot14::ONE]),
1895
                None
1896
            );
1897
        }
1898
    }
1899
1900
    #[test]
1901
    fn implicit_advance_indices_do_not_truncate_glyph_ids() {
1902
        let bytes = BeBuffer::new()
1903
            .push(1u16) // ItemVariationStore format
1904
            .push(12u32) // region list offset
1905
            .push(1u16) // variation data count
1906
            .push(22u32) // variation data offset
1907
            .push(1u16) // axis count
1908
            .push(1u16) // region count
1909
            .extend([F2Dot14::ZERO, F2Dot14::ONE, F2Dot14::ONE])
1910
            .push(2u16) // item count
1911
            .push(1u16) // word delta count
1912
            .push(1u16) // region index count
1913
            .push(0u16) // region index
1914
            .extend([10i16, 100i16]);
1915
        let store = ItemVariationStore::read(FontData::new(&bytes)).unwrap();
1916
        let mapping = DeltaSetIndexMap::read(FontData::new(&[0, 0, 0, 1, 0])).unwrap();
1917
        let coords = [F2Dot14::from_f32(0.75)];
1918
        let mut scalars = [Fixed::ZERO; 32];
1919
        let scalar_count = store.compute_scalars(&coords, &mut scalars);
1920
        for scalars in [&[][..], &scalars[..scalar_count]] {
1921
            let delta = advance_delta_with_scalars(
1922
                None,
1923
                Ok(store.clone()),
1924
                GlyphId::new(1),
1925
                &coords,
1926
                scalars,
1927
            );
1928
            assert!(delta.is_some_and(|delta| delta != F48Dot16::ZERO));
1929
            for gid in [0xFFFF, 0x10000, 0x10001, 0xFFFF0001] {
1930
                assert_eq!(
1931
                    advance_delta_with_scalars(
1932
                        None,
1933
                        Ok(store.clone()),
1934
                        GlyphId::new(gid),
1935
                        &coords,
1936
                        scalars,
1937
                    ),
1938
                    Some(F48Dot16::ZERO),
1939
                    "implicit advance mapping wrapped glyph ID {gid}"
1940
                );
1941
            }
1942
            // Explicit mappings keep their last-entry repetition for high IDs.
1943
            for gid in [0x10000, 0x10001] {
1944
                assert_eq!(
1945
                    advance_delta_with_scalars(
1946
                        Some(Ok(mapping.clone())),
1947
                        Ok(store.clone()),
1948
                        GlyphId::new(gid),
1949
                        &coords,
1950
                        scalars,
1951
                    ),
1952
                    Some(F48Dot16::from_f64(7.5))
1953
                );
1954
            }
1955
        }
1956
    }
1957
1958
    #[test]
1959
    fn ivs_regions() {
1960
        let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1961
        let hvar = font.hvar().expect("missing HVAR table");
1962
        let ivs = hvar
1963
            .item_variation_store()
1964
            .expect("missing item variation store in HVAR");
1965
        let region_list = ivs.variation_region_list().expect("missing region list!");
1966
        let regions = region_list.variation_regions();
1967
        let expected = &[
1968
            // start_coord, peak_coord, end_coord
1969
            vec![[-1.0f32, -1.0, 0.0]],
1970
            vec![[0.0, 1.0, 1.0]],
1971
        ][..];
1972
        let region_coords = regions
1973
            .iter()
1974
            .map(|region| {
1975
                region
1976
                    .unwrap()
1977
                    .region_axes()
1978
                    .iter()
1979
                    .map(|coords| {
1980
                        [
1981
                            coords.start_coord().to_f32(),
1982
                            coords.peak_coord().to_f32(),
1983
                            coords.end_coord().to_f32(),
1984
                        ]
1985
                    })
1986
                    .collect::<Vec<_>>()
1987
            })
1988
            .collect::<Vec<_>>();
1989
        assert_eq!(expected, &region_coords);
1990
    }
1991
1992
    // A gvar/cvar intermediate region that does not enclose its own peak, or
1993
    // that straddles the default, must be ignored (contribute a factor of one)
1994
    // rather than interpolated. This matches the OpenType algorithm and the
1995
    // sibling `compute_scalar_f32` / `VariationRegion::compute_scalar`, which
1996
    // already apply the guard.
1997
    #[test]
1998
    fn scalar_for_ignores_invalid_intermediate_region() {
1999
        fn tuple(values: &[BigEndian<F2Dot14>]) -> Tuple<'_> {
2000
            Tuple { values }
2001
        }
2002
        let f = F2Dot14::from_f32;
2003
2004
        // start > peak: the coord sits inside (start, end) but the region does
2005
        // not contain the peak, so the axis is skipped. Before the guard this
2006
        // interpolated to (end - coord) / (end - peak) = 0.2.
2007
        let peak: [BigEndian<F2Dot14>; 1] = [f(0.5).into()];
2008
        let start: [BigEndian<F2Dot14>; 1] = [f(0.8).into()];
2009
        let end: [BigEndian<F2Dot14>; 1] = [f(1.0).into()];
2010
        let coords = [f(0.9)];
2011
        assert_eq!(
2012
            scalar_for(&tuple(&peak), Some((tuple(&start), tuple(&end))), &coords),
2013
            Some(Fixed::ONE)
2014
        );
2015
2016
        // peak > end.
2017
        let peak2: [BigEndian<F2Dot14>; 1] = [f(1.0).into()];
2018
        let start2: [BigEndian<F2Dot14>; 1] = [f(0.0).into()];
2019
        let end2: [BigEndian<F2Dot14>; 1] = [f(0.5).into()];
2020
        let coords2 = [f(0.25)];
2021
        assert_eq!(
2022
            scalar_for(
2023
                &tuple(&peak2),
2024
                Some((tuple(&start2), tuple(&end2))),
2025
                &coords2
2026
            ),
2027
            Some(Fixed::ONE)
2028
        );
2029
2030
        // Region straddling the default (start < 0 < end).
2031
        let start3: [BigEndian<F2Dot14>; 1] = [f(-0.5).into()];
2032
        let end3: [BigEndian<F2Dot14>; 1] = [f(1.0).into()];
2033
        let coords3 = [f(0.25)];
2034
        assert_eq!(
2035
            scalar_for(
2036
                &tuple(&peak),
2037
                Some((tuple(&start3), tuple(&end3))),
2038
                &coords3
2039
            ),
2040
            Some(Fixed::ONE)
2041
        );
2042
2043
        // A well-formed region (start <= peak <= end) still interpolates.
2044
        let start4: [BigEndian<F2Dot14>; 1] = [f(0.0).into()];
2045
        let end4: [BigEndian<F2Dot14>; 1] = [f(1.0).into()];
2046
        let coords4 = [f(0.25)];
2047
        let scalar = scalar_for(
2048
            &tuple(&peak),
2049
            Some((tuple(&start4), tuple(&end4))),
2050
            &coords4,
2051
        )
2052
        .unwrap();
2053
        assert!((scalar.to_f32() - 0.5).abs() < 1e-4);
2054
    }
2055
2056
    // adapted from https://github.com/fonttools/fonttools/blob/f73220816264fc383b8a75f2146e8d69e455d398/Tests/ttLib/tables/TupleVariation_test.py#L492
2057
    #[test]
2058
    fn packed_points() {
2059
        fn decode_points(bytes: &[u8]) -> Option<Vec<u16>> {
2060
            let data = FontData::new(bytes);
2061
            let packed = PackedPointNumbers { data };
2062
            if packed.count() == 0 {
2063
                None
2064
            } else {
2065
                Some(packed.iter().collect())
2066
            }
2067
        }
2068
2069
        assert_eq!(decode_points(&[0]), None);
2070
        // all points in glyph (in overly verbose encoding, not explicitly prohibited by spec)
2071
        assert_eq!(decode_points(&[0x80, 0]), None);
2072
        // 2 points; first run: [9, 9+6]
2073
        assert_eq!(decode_points(&[0x02, 0x01, 0x09, 0x06]), Some(vec![9, 15]));
2074
        // 2 points; first run: [0xBEEF, 0xCAFE]. (0x0C0F = 0xCAFE - 0xBEEF)
2075
        assert_eq!(
2076
            decode_points(&[0x02, 0x81, 0xbe, 0xef, 0x0c, 0x0f]),
2077
            Some(vec![0xbeef, 0xcafe])
2078
        );
2079
        // 1 point; first run: [7]
2080
        assert_eq!(decode_points(&[0x01, 0, 0x07]), Some(vec![7]));
2081
        // 1 point; first run: [7] in overly verbose encoding
2082
        assert_eq!(decode_points(&[0x01, 0x80, 0, 0x07]), Some(vec![7]));
2083
        // 1 point; first run: [65535]; requires words to be treated as unsigned numbers
2084
        assert_eq!(decode_points(&[0x01, 0x80, 0xff, 0xff]), Some(vec![65535]));
2085
        // 4 points; first run: [7, 8]; second run: [255, 257]. 257 is stored in delta-encoded bytes (0xFF + 2).
2086
        assert_eq!(
2087
            decode_points(&[0x04, 1, 7, 1, 1, 0xff, 2]),
2088
            Some(vec![7, 8, 263, 265])
2089
        );
2090
    }
2091
2092
    #[test]
2093
    fn packed_point_byte_len() {
2094
        fn count_bytes(bytes: &[u8]) -> usize {
2095
            let packed = PackedPointNumbers {
2096
                data: FontData::new(bytes),
2097
            };
2098
            packed.total_len()
2099
        }
2100
2101
        static CASES: &[&[u8]] = &[
2102
            &[0],
2103
            &[0x80, 0],
2104
            &[0x02, 0x01, 0x09, 0x06],
2105
            &[0x02, 0x81, 0xbe, 0xef, 0x0c, 0x0f],
2106
            &[0x01, 0, 0x07],
2107
            &[0x01, 0x80, 0, 0x07],
2108
            &[0x01, 0x80, 0xff, 0xff],
2109
            &[0x04, 1, 7, 1, 1, 0xff, 2],
2110
        ];
2111
2112
        for case in CASES {
2113
            assert_eq!(count_bytes(case), case.len(), "{case:?}");
2114
        }
2115
    }
2116
2117
    // https://github.com/fonttools/fonttools/blob/c30a6355ffdf7f09d31e7719975b4b59bac410af/Tests/ttLib/tables/TupleVariation_test.py#L670
2118
    #[test]
2119
    fn packed_deltas() {
2120
        static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
2121
2122
        let deltas = PackedDeltas::consume_all(INPUT);
2123
        assert_eq!(deltas.count_or_compute(), 7);
2124
        assert_eq!(
2125
            deltas.iter().collect::<Vec<_>>(),
2126
            &[0, 0, 0, 0, 258, -127, -128]
2127
        );
2128
2129
        assert_eq!(
2130
            PackedDeltas::consume_all(FontData::new(&[0x81]))
2131
                .iter()
2132
                .collect::<Vec<_>>(),
2133
            &[0, 0,]
2134
        );
2135
    }
2136
2137
    // https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-deltas
2138
    #[test]
2139
    fn packed_deltas_spec() {
2140
        static INPUT: FontData = FontData::new(&[
2141
            0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
2142
        ]);
2143
        static EXPECTED: &[i32] = &[10, -105, 0, -58, 0, 0, 0, 0, 0, 0, 0, 0, 4130, -1228];
2144
2145
        let deltas = PackedDeltas::consume_all(INPUT);
2146
        assert_eq!(deltas.count_or_compute(), EXPECTED.len());
2147
        assert_eq!(deltas.iter().collect::<Vec<_>>(), EXPECTED);
2148
    }
2149
2150
    #[test]
2151
    fn packed_delta_fetcher_skip_matches_iterator_suffix() {
2152
        static INPUT: FontData = FontData::new(&[
2153
            0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
2154
        ]);
2155
        let deltas = PackedDeltas::consume_all(INPUT);
2156
        let expected = deltas.iter().collect::<Vec<_>>();
2157
2158
        for skip in 0..=expected.len() {
2159
            let mut fetcher = deltas.fetcher();
2160
            fetcher.skip(skip).unwrap();
2161
            let mut out = vec![0.0; expected.len() - skip];
2162
            fetcher.add_to_f32_scaled(&mut out, 1.0).unwrap();
2163
            let got = out.into_iter().map(|v| v as i32).collect::<Vec<_>>();
2164
            assert_eq!(&got[..], &expected[skip..], "skip={skip}");
2165
        }
2166
2167
        let mut fetcher = deltas.fetcher();
2168
        assert!(matches!(
2169
            fetcher.skip(expected.len() + 1),
2170
            Err(ReadError::OutOfBounds)
2171
        ));
2172
    }
2173
2174
    #[test]
2175
    fn packed_delta_fetcher_scaled_add_and_exhaustion() {
2176
        static INPUT: FontData = FontData::new(&[
2177
            0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
2178
        ]);
2179
        // First four deltas are [10, -105, 0, -58].
2180
        let deltas = PackedDeltas::new(INPUT, 4);
2181
        let mut fetcher = deltas.fetcher();
2182
        let mut out = [1.0f32; 4];
2183
        fetcher.add_to_f32_scaled(&mut out, 0.5).unwrap();
2184
        assert_eq!(out, [6.0, -51.5, 1.0, -28.0]);
2185
2186
        // Bounded fetcher should now be exhausted.
2187
        let mut extra = [0.0f32; 1];
2188
        assert!(matches!(
2189
            fetcher.add_to_f32_scaled(&mut extra, 1.0),
2190
            Err(ReadError::OutOfBounds)
2191
        ));
2192
    }
2193
2194
    #[test]
2195
    fn packed_delta_fetcher_f64_preserves_i32_residuals() {
2196
        static INPUT: FontData =
2197
            FontData::new(&[0xC1, 0x01, 0x00, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x00]);
2198
        let mut fetcher = PackedDeltas::new(INPUT, 2).fetcher();
2199
        let mut out = [0.0f64];
2200
        fetcher.add_to_f64_scaled(&mut out, 0.5).unwrap();
2201
        fetcher.add_to_f64_scaled(&mut out, 0.5).unwrap();
2202
        assert_eq!(out, [0.5]);
2203
        assert!(matches!(
2204
            fetcher.add_to_f64_scaled(&mut out, 1.0),
2205
            Err(ReadError::OutOfBounds)
2206
        ));
2207
    }
2208
2209
    #[test]
2210
    fn packed_delta_fetcher_skip_then_add_bounded() {
2211
        static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
2212
        // Full decoded stream: [0, 0, 0, 0, 258, -127, -128]
2213
        let deltas = PackedDeltas::new(INPUT, 7);
2214
        let mut fetcher = deltas.fetcher();
2215
        fetcher.skip(3).unwrap();
2216
        let mut out = [0.0f32; 4];
2217
        fetcher.add_to_f32_scaled(&mut out, 1.0).unwrap();
2218
        assert_eq!(out, [0.0, 258.0, -127.0, -128.0]);
2219
    }
2220
2221
    #[test]
2222
    fn delta_run_iter_end_exhausts_unbounded_data() {
2223
        static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
2224
        let deltas = PackedDeltas::consume_all(INPUT);
2225
        let end = deltas.iter().end();
2226
        assert_eq!(end.remaining_bytes(), 0);
2227
    }
2228
2229
    #[test]
2230
    fn delta_run_iter_end_respects_bounded_count() {
2231
        static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
2232
        // Count is exactly the first run only (4 zeros), so end() should not consume past
2233
        // the run header byte.
2234
        let deltas = PackedDeltas::new(INPUT, 4);
2235
        let end = deltas.iter().end();
2236
        assert_eq!(end.remaining_bytes(), INPUT.len() - 1);
2237
2238
        let end_via_skip = deltas.iter().skip_fast(4).cursor;
2239
        assert_eq!(end_via_skip.remaining_bytes(), INPUT.len() - 1);
2240
    }
2241
2242
    #[test]
2243
    fn delta_run_iter_end_matches_manual_iteration_for_bounded_data() {
2244
        static INPUT: FontData = FontData::new(&[
2245
            0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
2246
        ]);
2247
        let deltas = PackedDeltas::new(INPUT, 6);
2248
2249
        let iter_collected = deltas.iter().collect::<Vec<_>>();
2250
        assert_eq!(iter_collected.len(), 6);
2251
2252
        let end = deltas.iter().end();
2253
        let end_via_skip = deltas.iter().skip_fast(6).cursor;
2254
        assert_eq!(end.remaining_bytes(), end_via_skip.remaining_bytes());
2255
    }
2256
2257
    fn lcg_next(state: &mut u32) -> u32 {
2258
        *state = state.wrapping_mul(1664525).wrapping_add(1013904223);
2259
        *state
2260
    }
2261
2262
    fn generated_delta_stream(seed: u32) -> (Vec<u8>, Vec<i32>) {
2263
        let mut state = seed;
2264
        let mut bytes = Vec::new();
2265
        let mut expected = Vec::new();
2266
        let run_count = (lcg_next(&mut state) % 6 + 1) as usize;
2267
        for _ in 0..run_count {
2268
            let run_type = (lcg_next(&mut state) % 4) as usize;
2269
            let len = (lcg_next(&mut state) % 8 + 1) as usize;
2270
            let control = match run_type {
2271
                0 => (len - 1) as u8,        // i8
2272
                1 => 0x40 | (len - 1) as u8, // i16
2273
                2 => 0x80 | (len - 1) as u8, // zero
2274
                _ => 0xC0 | (len - 1) as u8, // i32
2275
            };
2276
            bytes.push(control);
2277
            match run_type {
2278
                0 => {
2279
                    for _ in 0..len {
2280
                        let v = ((lcg_next(&mut state) % 255) as i32 - 127) as i8;
2281
                        bytes.push(v as u8);
2282
                        expected.push(v as i32);
2283
                    }
2284
                }
2285
                1 => {
2286
                    for _ in 0..len {
2287
                        let v = ((lcg_next(&mut state) % 65535) as i32 - 32767) as i16;
2288
                        bytes.extend(v.to_be_bytes());
2289
                        expected.push(v as i32);
2290
                    }
2291
                }
2292
                2 => {
2293
                    expected.resize(expected.len() + len, 0);
2294
                }
2295
                _ => {
2296
                    for _ in 0..len {
2297
                        let v = (lcg_next(&mut state) % 2_000_001) as i32 - 1_000_000;
2298
                        bytes.extend(v.to_be_bytes());
2299
                        expected.push(v);
2300
                    }
2301
                }
2302
            }
2303
        }
2304
        (bytes, expected)
2305
    }
2306
2307
    #[test]
2308
    fn generated_packed_deltas_iter_matches_expected() {
2309
        for seed in 1..=64 {
2310
            let (bytes, expected) = generated_delta_stream(seed);
2311
            let data = FontData::new(&bytes);
2312
            let deltas = PackedDeltas::consume_all(data);
2313
            assert_eq!(deltas.count_or_compute(), expected.len(), "seed={seed}");
2314
            assert_eq!(deltas.iter().collect::<Vec<_>>(), expected, "seed={seed}");
2315
        }
2316
    }
2317
2318
    #[test]
2319
    fn generated_fetcher_skip_scaled_matches_expected() {
2320
        for seed in 1..=64 {
2321
            let (bytes, expected) = generated_delta_stream(seed);
2322
            let data = FontData::new(&bytes);
2323
            let deltas = PackedDeltas::new(data, expected.len());
2324
            let mut fetcher = deltas.fetcher();
2325
            let skip = (seed as usize * 7) % (expected.len() + 1);
2326
            fetcher.skip(skip).unwrap();
2327
2328
            let scale = if seed % 2 == 0 { 0.25 } else { -0.5 };
2329
            let mut out = vec![10.0f32; expected.len() - skip];
2330
            fetcher.add_to_f32_scaled(&mut out, scale).unwrap();
2331
            for (i, got) in out.iter().copied().enumerate() {
2332
                let want = 10.0 + expected[skip + i] as f32 * scale;
2333
                assert!(
2334
                    (got - want).abs() <= 1e-6,
2335
                    "seed={seed} i={i} got={got} want={want}"
2336
                );
2337
            }
2338
2339
            // Bounded fetcher should be exhausted after consuming all remaining entries.
2340
            let mut extra = [0.0f32; 1];
2341
            assert!(matches!(
2342
                fetcher.add_to_f32_scaled(&mut extra, 1.0),
2343
                Err(ReadError::OutOfBounds)
2344
            ));
2345
        }
2346
    }
2347
2348
    #[test]
2349
    fn packed_point_split() {
2350
        static INPUT: FontData =
2351
            FontData::new(&[2, 1, 1, 2, 1, 205, 143, 1, 8, 0, 1, 202, 59, 1, 255, 0]);
2352
        let (points, data) = PackedPointNumbers::split_off_front(INPUT);
2353
        assert_eq!(points.count(), 2);
2354
        assert_eq!(points.iter().collect::<Vec<_>>(), &[1, 3]);
2355
        assert_eq!(points.total_len(), 4);
2356
        assert_eq!(data.len(), INPUT.len() - 4);
2357
    }
2358
2359
    #[test]
2360
    fn packed_points_dont_panic() {
2361
        // a single '0' byte means that there are deltas for all points
2362
        static ALL_POINTS: FontData = FontData::new(&[0]);
2363
        let (all_points, _) = PackedPointNumbers::split_off_front(ALL_POINTS);
2364
        // in which case the iterator just keeps incrementing until u16::MAX
2365
        assert_eq!(all_points.iter().count(), u16::MAX as usize);
2366
    }
2367
2368
    /// Test that we split properly when the coordinate boundary doesn't align
2369
    /// with a packed run boundary
2370
    #[test]
2371
    fn packed_delta_run_crosses_coord_boundary() {
2372
        // 8 deltas with values 0..=7 with a run broken after the first 6; the
2373
        // coordinate boundary occurs after the first 4
2374
        static INPUT: FontData = FontData::new(&[
2375
            // first run: 6 deltas as bytes
2376
            5,
2377
            0,
2378
            1,
2379
            2,
2380
            3,
2381
            // coordinate boundary is here
2382
            4,
2383
            5,
2384
            // second run: 2 deltas as words
2385
            1 | DELTAS_ARE_WORDS,
2386
            0,
2387
            6,
2388
            0,
2389
            7,
2390
        ]);
2391
        let deltas = PackedDeltas::consume_all(INPUT);
2392
        assert_eq!(deltas.count_or_compute(), 8);
2393
        let x_deltas = deltas.x_deltas().collect::<Vec<_>>();
2394
        let y_deltas = deltas.y_deltas().collect::<Vec<_>>();
2395
        assert_eq!(x_deltas, [0, 1, 2, 3]);
2396
        assert_eq!(y_deltas, [4, 5, 6, 7]);
2397
    }
2398
2399
    /// We don't have a reference for our float delta computation, so this is
2400
    /// a sanity test to ensure that floating point deltas are within a
2401
    /// reasonable margin of the same in fixed point.
2402
    #[test]
2403
    fn ivs_float_deltas_nearly_match_fixed_deltas() {
2404
        let font = FontRef::new(font_test_data::COLRV0V1_VARIABLE).unwrap();
2405
        let axis_count = font.fvar().unwrap().axis_count() as usize;
2406
        let colr = font.colr().unwrap();
2407
        let ivs = colr.item_variation_store().unwrap().unwrap();
2408
        // Generate a set of coords from -1 to 1 in 0.1 increments
2409
        for coord in (0..=20).map(|x| F2Dot14::from_f32((x as f32) / 10.0 - 1.0)) {
2410
            // For testing purposes, just splat the coord to all axes
2411
            let coords = vec![coord; axis_count];
2412
            for (outer_ix, data) in ivs.item_variation_data().iter().enumerate() {
2413
                let outer_ix = outer_ix as u16;
2414
                let Some(Ok(data)) = data else {
2415
                    continue;
2416
                };
2417
                for inner_ix in 0..data.item_count() {
2418
                    let delta_ix = DeltaSetIndex {
2419
                        outer: outer_ix,
2420
                        inner: inner_ix,
2421
                    };
2422
                    // Check the deltas against all possible target values
2423
                    let delta = ivs.compute_delta(delta_ix, &coords).unwrap();
2424
                    let orig_delta = delta.to_i32();
2425
                    let float_delta = delta.to_f64();
2426
2427
                    // For font unit types, we need to accept both rounding and
2428
                    // truncation to account for the additional accumulation of
2429
                    // fractional bits in floating point
2430
                    assert!(
2431
                        orig_delta == float_delta.round() as i32
2432
                            || orig_delta == float_delta.trunc() as i32
2433
                    );
2434
                    // For the fixed point types, check with an epsilon
2435
                    const EPSILON: f32 = 1e12;
2436
                    let fixed_delta = Fixed::ZERO.apply_delta(delta);
2437
                    assert!((Fixed::from_bits(orig_delta).to_f32() - fixed_delta).abs() < EPSILON);
2438
                    let f2dot14_delta = F2Dot14::ZERO.apply_delta(delta);
2439
                    assert!(
2440
                        (F2Dot14::from_bits(orig_delta as i16).to_f32() - f2dot14_delta).abs()
2441
                            < EPSILON
2442
                    );
2443
                }
2444
            }
2445
        }
2446
    }
2447
2448
    #[test]
2449
    fn ivs_data_len_short() {
2450
        let data = BeBuffer::new()
2451
            .push(2u16) // item_count
2452
            .push(3u16) // word_delta_count
2453
            .push(5u16) // region_index_count
2454
            .extend([0u16, 1, 2, 3, 4]) // region_indices
2455
            .extend([1u8; 128]); // this is much more data than we need!
2456
2457
        let ivs = ItemVariationData::read(data.data().into()).unwrap();
2458
        let row_len = (3 * u16::RAW_BYTE_LEN) + (2 * u8::RAW_BYTE_LEN); // 3 word deltas, 2 byte deltas
2459
        let expected_len = 2 * row_len;
2460
        assert_eq!(ivs.delta_sets().len(), expected_len);
2461
    }
2462
2463
    #[test]
2464
    fn ivs_data_len_long() {
2465
        let data = BeBuffer::new()
2466
            .push(2u16) // item_count
2467
            .push(2u16 | 0x8000) // word_delta_count, long deltas
2468
            .push(4u16) // region_index_count
2469
            .extend([0u16, 1, 2]) // region_indices
2470
            .extend([1u8; 128]); // this is much more data than we need!
2471
2472
        let ivs = ItemVariationData::read(data.data().into()).unwrap();
2473
        let row_len = (2 * u32::RAW_BYTE_LEN) + (2 * u16::RAW_BYTE_LEN); // 1 word (4-byte) delta, 2 short (2-byte)
2474
        let expected_len = 2 * row_len;
2475
        assert_eq!(ivs.delta_sets().len(), expected_len);
2476
    }
2477
2478
    // Add with overflow when accumulating packed point numbers
2479
    // https://issues.oss-fuzz.com/issues/378159154
2480
    #[test]
2481
    fn packed_point_numbers_avoid_overflow() {
2482
        // Lots of 1 bits triggers the behavior quite nicely
2483
        let buf = vec![0xFF; 0xFFFF];
2484
        let iter = PackedPointNumbersIter::new(0xFFFF, FontData::new(&buf).cursor());
2485
        // Don't panic!
2486
        let _ = iter.count();
2487
    }
2488
2489
    // Dense accumulator should match iterator
2490
    #[test]
2491
    fn accumulate_dense() {
2492
        let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
2493
        let gvar = font.gvar().unwrap();
2494
        let gvar_data = gvar.glyph_variation_data(GlyphId::new(1)).unwrap().unwrap();
2495
        let mut count = 0;
2496
        for tuple in gvar_data.tuples() {
2497
            if !tuple.has_deltas_for_all_points() {
2498
                continue;
2499
            }
2500
            let iter_deltas = tuple
2501
                .deltas()
2502
                .map(|delta| (delta.x_delta, delta.y_delta))
2503
                .collect::<Vec<_>>();
2504
            let mut delta_buf = vec![Point::broadcast(Fixed::ZERO); iter_deltas.len()];
2505
            tuple
2506
                .accumulate_dense_deltas(&mut delta_buf, Fixed::ONE)
2507
                .unwrap();
2508
            let accum_deltas = delta_buf
2509
                .iter()
2510
                .map(|delta| (delta.x.to_i32(), delta.y.to_i32()))
2511
                .collect::<Vec<_>>();
2512
            assert_eq!(iter_deltas, accum_deltas);
2513
            count += iter_deltas.len();
2514
        }
2515
        assert!(count != 0);
2516
    }
2517
2518
    // Sparse accumulator should match iterator
2519
    #[test]
2520
    fn accumulate_sparse() {
2521
        let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
2522
        let gvar = font.gvar().unwrap();
2523
        let gvar_data = gvar.glyph_variation_data(GlyphId::new(2)).unwrap().unwrap();
2524
        let mut count = 0;
2525
        for tuple in gvar_data.tuples() {
2526
            if tuple.has_deltas_for_all_points() {
2527
                continue;
2528
            }
2529
            let iter_deltas = tuple.deltas().collect::<Vec<_>>();
2530
            let max_modified_point = iter_deltas
2531
                .iter()
2532
                .max_by_key(|delta| delta.position)
2533
                .unwrap()
2534
                .position as usize;
2535
            let mut delta_buf = vec![Point::broadcast(Fixed::ZERO); max_modified_point + 1];
2536
            let mut flags = vec![PointFlags::default(); delta_buf.len()];
2537
            tuple
2538
                .accumulate_sparse_deltas(&mut delta_buf, &mut flags, Fixed::ONE)
2539
                .unwrap();
2540
            let mut accum_deltas = vec![];
2541
            for (i, (delta, flag)) in delta_buf.iter().zip(flags).enumerate() {
2542
                if flag.has_marker(PointMarker::HAS_DELTA) {
2543
                    accum_deltas.push(GlyphDelta::new(
2544
                        i as u16,
2545
                        delta.x.to_i32(),
2546
                        delta.y.to_i32(),
2547
                    ));
2548
                }
2549
            }
2550
            assert_eq!(iter_deltas, accum_deltas);
2551
            count += iter_deltas.len();
2552
        }
2553
        assert!(count != 0);
2554
    }
2555
2556
    #[test]
2557
    fn delta_set_index_map_empty_is_identity() {
2558
        let data = BeBuffer::new()
2559
            .push(0u8) // format 0
2560
            .push(EntryFormat::empty())
2561
            .push(0u16); // map_count
2562
        let map = DeltaSetIndexMap::read(data.data().into()).unwrap();
2563
        assert_eq!(
2564
            map.get(0x0001_0002).unwrap(),
2565
            DeltaSetIndex { outer: 1, inner: 2 }
2566
        );
2567
    }
2568
}