1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use core::convert::TryFrom;
use core::num::NonZeroU16;
use crate::NormalizedCoord;
use crate::parser::{Stream, FromData, LazyArray16};
#[derive(Clone, Copy)]
pub(crate) struct Table<'a> {
axis_count: NonZeroU16,
data: &'a [u8],
}
impl<'a> Table<'a> {
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let version: u32 = s.read()?;
if version != 0x00010000 {
return None;
}
s.skip::<u16>();
let axis_count: u16 = s.read()?;
let axis_count = NonZeroU16::new(axis_count)?;
let data = s.tail()?;
for _ in 0..axis_count.get() {
let count: u16 = s.read()?;
s.advance_checked(AxisValueMapRecord::SIZE * usize::from(count))?;
}
Some(Table {
axis_count,
data,
})
}
pub fn map_coordinates(&self, coordinates: &mut [NormalizedCoord]) -> Option<()> {
if usize::from(self.axis_count.get()) != coordinates.len() {
return None;
}
let mut s = Stream::new(self.data);
for coord in coordinates {
let count: u16 = s.read()?;
let map = s.read_array16::<AxisValueMapRecord>(count)?;
*coord = NormalizedCoord::from(map_value(&map, coord.0)?);
}
Some(())
}
}
fn map_value(map: &LazyArray16<AxisValueMapRecord>, value: i16) -> Option<i16> {
if map.len() == 0 {
return Some(value);
} else if map.len() == 1 {
let record = map.get(0)?;
return Some(value - record.from_coordinate + record.to_coordinate);
}
let record_0 = map.get(0)?;
if value <= record_0.from_coordinate {
return Some(value - record_0.from_coordinate + record_0.to_coordinate);
}
let mut i = 1;
while i < map.len() && value > map.get(i)?.from_coordinate {
i += 1;
}
if i == map.len() {
i -= 1;
}
let record_curr = map.get(i)?;
let curr_from = record_curr.from_coordinate;
let curr_to = record_curr.to_coordinate;
if value >= curr_from {
return Some(value - curr_from + curr_to);
}
let record_prev = map.get(i - 1)?;
let prev_from = record_prev.from_coordinate;
let prev_to = record_prev.to_coordinate;
if prev_from == curr_from {
return Some(prev_to);
}
let curr_from = i32::from(curr_from);
let curr_to = i32::from(curr_to);
let prev_from = i32::from(prev_from);
let prev_to = i32::from(prev_to);
let denom = curr_from - prev_from;
let k = (curr_to - prev_to) * (i32::from(value) - prev_from) + denom / 2;
let value = prev_to + k / denom;
i16::try_from(value).ok()
}
#[derive(Clone, Copy)]
struct AxisValueMapRecord {
from_coordinate: i16,
to_coordinate: i16,
}
impl FromData for AxisValueMapRecord {
const SIZE: usize = 4;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(AxisValueMapRecord {
from_coordinate: s.read()?,
to_coordinate: s.read()?,
})
}
}