1 //! A GPOS ValueRecord
2 
3 use font_types::Nullable;
4 use types::{BigEndian, FixedSize, Offset16};
5 
6 use super::ValueFormat;
7 use crate::{tables::layout::DeviceOrVariationIndex, ResolveNullableOffset};
8 
9 #[cfg(feature = "traversal")]
10 use crate::traversal::{Field, FieldType, RecordResolver, SomeRecord};
11 use crate::{ComputeSize, FontData, FontReadWithArgs, ReadArgs, ReadError};
12 
13 impl ValueFormat {
14     /// A mask with all the device/variation index bits set
15     pub const ANY_DEVICE_OR_VARIDX: Self = ValueFormat {
16         bits: 0x0010 | 0x0020 | 0x0040 | 0x0080,
17     };
18 
19     /// Return the number of bytes required to store a [`ValueRecord`] in this format.
20     #[inline]
record_byte_len(self) -> usize21     pub fn record_byte_len(self) -> usize {
22         self.bits().count_ones() as usize * u16::RAW_BYTE_LEN
23     }
24 }
25 
26 /// A Positioning ValueRecord.
27 ///
28 /// NOTE: we create these manually, since parsing is weird and depends on the
29 /// associated valueformat. That said, this isn't a great representation?
30 /// we could definitely do something much more in the zero-copy mode..
31 #[derive(Clone, Default, PartialEq, Eq)]
32 pub struct ValueRecord {
33     pub x_placement: Option<BigEndian<i16>>,
34     pub y_placement: Option<BigEndian<i16>>,
35     pub x_advance: Option<BigEndian<i16>>,
36     pub y_advance: Option<BigEndian<i16>>,
37     pub x_placement_device: BigEndian<Nullable<Offset16>>,
38     pub y_placement_device: BigEndian<Nullable<Offset16>>,
39     pub x_advance_device: BigEndian<Nullable<Offset16>>,
40     pub y_advance_device: BigEndian<Nullable<Offset16>>,
41 }
42 
43 impl ValueRecord {
read_old(data: &[u8], format: ValueFormat) -> Result<Self, ReadError>44     pub fn read_old(data: &[u8], format: ValueFormat) -> Result<Self, ReadError> {
45         let data = FontData::new(data);
46         Self::read(data, format)
47     }
48 
read(data: FontData, format: ValueFormat) -> Result<Self, ReadError>49     pub fn read(data: FontData, format: ValueFormat) -> Result<Self, ReadError> {
50         let mut this = ValueRecord::default();
51         let mut cursor = data.cursor();
52 
53         if format.contains(ValueFormat::X_PLACEMENT) {
54             this.x_placement = Some(cursor.read_be()?);
55         }
56         if format.contains(ValueFormat::Y_PLACEMENT) {
57             this.y_placement = Some(cursor.read_be()?);
58         }
59         if format.contains(ValueFormat::X_ADVANCE) {
60             this.x_advance = Some(cursor.read_be()?);
61         }
62         if format.contains(ValueFormat::Y_ADVANCE) {
63             this.y_advance = Some(cursor.read_be()?);
64         }
65         if format.contains(ValueFormat::X_PLACEMENT_DEVICE) {
66             this.x_placement_device = cursor.read_be()?;
67         }
68         if format.contains(ValueFormat::Y_PLACEMENT_DEVICE) {
69             this.y_placement_device = cursor.read_be()?;
70         }
71         if format.contains(ValueFormat::X_ADVANCE_DEVICE) {
72             this.x_advance_device = cursor.read_be()?;
73         }
74         if format.contains(ValueFormat::Y_ADVANCE_DEVICE) {
75             this.y_advance_device = cursor.read_be()?;
76         }
77         Ok(this)
78     }
79 
x_placement(&self) -> Option<i16>80     pub fn x_placement(&self) -> Option<i16> {
81         self.x_placement.map(|val| val.get())
82     }
83 
y_placement(&self) -> Option<i16>84     pub fn y_placement(&self) -> Option<i16> {
85         self.y_placement.map(|val| val.get())
86     }
87 
x_advance(&self) -> Option<i16>88     pub fn x_advance(&self) -> Option<i16> {
89         self.x_advance.map(|val| val.get())
90     }
91 
y_advance(&self) -> Option<i16>92     pub fn y_advance(&self) -> Option<i16> {
93         self.y_advance.map(|val| val.get())
94     }
95 
x_placement_device<'a>( &self, data: FontData<'a>, ) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>>96     pub fn x_placement_device<'a>(
97         &self,
98         data: FontData<'a>,
99     ) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
100         self.x_placement_device.get().resolve(data)
101     }
102 
y_placement_device<'a>( &self, data: FontData<'a>, ) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>>103     pub fn y_placement_device<'a>(
104         &self,
105         data: FontData<'a>,
106     ) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
107         self.y_placement_device.get().resolve(data)
108     }
109 
x_advance_device<'a>( &self, data: FontData<'a>, ) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>>110     pub fn x_advance_device<'a>(
111         &self,
112         data: FontData<'a>,
113     ) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
114         self.x_advance_device.get().resolve(data)
115     }
116 
y_advance_device<'a>( &self, data: FontData<'a>, ) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>>117     pub fn y_advance_device<'a>(
118         &self,
119         data: FontData<'a>,
120     ) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
121         self.y_advance_device.get().resolve(data)
122     }
123 }
124 
125 impl ReadArgs for ValueRecord {
126     type Args = ValueFormat;
127 }
128 
129 impl<'a> FontReadWithArgs<'a> for ValueRecord {
read_with_args(data: FontData<'a>, args: &Self::Args) -> Result<Self, ReadError>130     fn read_with_args(data: FontData<'a>, args: &Self::Args) -> Result<Self, ReadError> {
131         ValueRecord::read(data, *args)
132     }
133 }
134 
135 impl std::fmt::Debug for ValueRecord {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result136     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
137         let mut f = f.debug_struct("ValueRecord");
138         self.x_placement.map(|x| f.field("x_placement", &x));
139         self.y_placement.map(|y| f.field("y_placement", &y));
140         self.x_advance.map(|x| f.field("x_advance", &x));
141         self.y_advance.map(|y| f.field("y_advance", &y));
142         if !self.x_placement_device.get().is_null() {
143             f.field("x_placement_device", &self.x_placement_device.get());
144         }
145         if !self.y_placement_device.get().is_null() {
146             f.field("y_placement_device", &self.y_placement_device.get());
147         }
148         if !self.x_advance_device.get().is_null() {
149             f.field("x_advance_device", &self.x_advance_device.get());
150         }
151         if !self.y_advance_device.get().is_null() {
152             f.field("y_advance_device", &self.y_advance_device.get());
153         }
154         f.finish()
155     }
156 }
157 
158 impl ComputeSize for ValueRecord {
159     #[inline]
compute_size(args: &ValueFormat) -> usize160     fn compute_size(args: &ValueFormat) -> usize {
161         args.record_byte_len()
162     }
163 }
164 
165 #[cfg(feature = "traversal")]
166 impl<'a> ValueRecord {
traversal_type(&self, data: FontData<'a>) -> FieldType<'a>167     pub(crate) fn traversal_type(&self, data: FontData<'a>) -> FieldType<'a> {
168         FieldType::Record(self.clone().traverse(data))
169     }
170 
get_field(&self, idx: usize, data: FontData<'a>) -> Option<Field<'a>>171     pub(crate) fn get_field(&self, idx: usize, data: FontData<'a>) -> Option<Field<'a>> {
172         let fields = [
173             self.x_placement.is_some().then_some("x_placement"),
174             self.y_placement.is_some().then_some("y_placement"),
175             self.x_advance.is_some().then_some("x_advance"),
176             self.y_advance.is_some().then_some("y_advance"),
177             (!self.x_placement_device.get().is_null()).then_some("x_placement_device"),
178             (!self.y_placement_device.get().is_null()).then_some("y_placement_device"),
179             (!self.x_advance_device.get().is_null()).then_some("x_advance_device"),
180             (!self.y_advance_device.get().is_null()).then_some("y_advance_device"),
181         ];
182 
183         let name = fields.iter().filter_map(|x| *x).nth(idx)?;
184         let typ: FieldType = match name {
185             "x_placement" => self.x_placement().unwrap().into(),
186             "y_placement" => self.y_placement().unwrap().into(),
187             "x_advance" => self.x_advance().unwrap().into(),
188             "y_advance" => self.y_advance().unwrap().into(),
189             "x_placement_device" => {
190                 FieldType::offset(self.x_placement_device.get(), self.x_placement_device(data))
191             }
192             "y_placement_device" => {
193                 FieldType::offset(self.y_placement_device.get(), self.y_placement_device(data))
194             }
195             "x_advance_device" => {
196                 FieldType::offset(self.x_advance_device.get(), self.x_advance_device(data))
197             }
198             "y_advance_device" => {
199                 FieldType::offset(self.y_advance_device.get(), self.y_advance_device(data))
200             }
201             _ => panic!("hmm"),
202         };
203 
204         Some(Field::new(name, typ))
205     }
206 }
207 
208 #[cfg(feature = "traversal")]
209 impl<'a> SomeRecord<'a> for ValueRecord {
traverse(self, data: FontData<'a>) -> RecordResolver<'a>210     fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
211         RecordResolver {
212             name: "ValueRecord",
213             data,
214             get_field: Box::new(move |idx, data| self.get_field(idx, data)),
215         }
216     }
217 }
218 
219 #[cfg(test)]
220 mod tests {
221     use super::*;
222 
223     #[test]
sanity_check_format_const()224     fn sanity_check_format_const() {
225         let format = ValueFormat::X_ADVANCE_DEVICE
226             | ValueFormat::Y_ADVANCE_DEVICE
227             | ValueFormat::Y_PLACEMENT_DEVICE
228             | ValueFormat::X_PLACEMENT_DEVICE;
229         assert_eq!(format, ValueFormat::ANY_DEVICE_OR_VARIDX);
230         assert_eq!(format.record_byte_len(), 4 * 2);
231     }
232 }
233