1 //! Implementation of Item Variation Store 2 //! 3 //! https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#item-variation-store 4 5 use crate::NormalizedCoord; 6 use crate::parser::{Stream, FromData, LazyArray16, NumFrom}; 7 8 9 #[derive(Clone, Copy)] 10 pub(crate) struct ItemVariationStore<'a> { 11 data: &'a [u8], 12 data_offsets: LazyArray16<'a, u32>, 13 pub regions: VariationRegionList<'a>, 14 } 15 16 impl<'a> Default for ItemVariationStore<'a> { 17 #[inline] default() -> Self18 fn default() -> Self { 19 ItemVariationStore { 20 data: &[], 21 data_offsets: LazyArray16::new(&[]), 22 regions: VariationRegionList { 23 axis_count: 0, 24 regions: LazyArray16::new(&[]), 25 } 26 } 27 } 28 } 29 30 impl<'a> ItemVariationStore<'a> { 31 #[inline] parse(mut s: Stream) -> Option<ItemVariationStore>32 pub fn parse(mut s: Stream) -> Option<ItemVariationStore> { 33 let data = s.tail()?; 34 35 let mut regions_s = s.clone(); 36 let format: u16 = s.read()?; 37 if format != 1 { 38 return None; 39 } 40 41 let region_list_offset: u32 = s.read()?; 42 let count: u16 = s.read()?; 43 let offsets = s.read_array16::<u32>(count)?; 44 45 let regions = { 46 regions_s.advance(usize::num_from(region_list_offset)); 47 // TODO: should be the same as in `fvar` 48 let axis_count = regions_s.read::<u16>()?; 49 let count = regions_s.read::<u16>()?; 50 let total = count.checked_mul(axis_count)?; 51 VariationRegionList { 52 axis_count, 53 regions: regions_s.read_array16(total)?, 54 } 55 }; 56 57 Some(ItemVariationStore { data, data_offsets: offsets, regions }) 58 } 59 region_indices(&self, index: u16) -> Option<LazyArray16<u16>>60 pub fn region_indices(&self, index: u16) -> Option<LazyArray16<u16>> { 61 // Offsets in bytes from the start of the item variation store 62 // to each item variation data subtable. 63 let offset = self.data_offsets.get(index)?; 64 let mut s = Stream::new_at(self.data, usize::num_from(offset))?; 65 s.skip::<u16>(); // item_count 66 s.skip::<u16>(); // short_delta_count 67 let count: u16 = s.read()?; 68 s.read_array16(count) 69 } 70 parse_delta( &self, outer_index: u16, inner_index: u16, coordinates: &[NormalizedCoord], ) -> Option<f32>71 pub fn parse_delta( 72 &self, 73 outer_index: u16, 74 inner_index: u16, 75 coordinates: &[NormalizedCoord], 76 ) -> Option<f32> { 77 let offset = self.data_offsets.get(outer_index)?; 78 let mut s = Stream::new_at(self.data, usize::num_from(offset))?; 79 let item_count: u16 = s.read()?; 80 let short_delta_count: u16 = s.read()?; 81 let region_index_count: u16 = s.read()?; 82 let region_indices = s.read_array16(region_index_count)?; 83 84 if inner_index >= item_count { 85 return None; 86 } 87 88 let delta_set_len = usize::from(short_delta_count) + usize::from(region_index_count); 89 s.advance(usize::from(inner_index).checked_mul(delta_set_len)?); 90 91 let mut delta = 0.0; 92 let mut i = 0; 93 while i < short_delta_count { 94 let idx = region_indices.get(i)?; 95 delta += f32::from(s.read::<i16>()?) * self.regions.evaluate_region(idx, coordinates); 96 i += 1; 97 } 98 99 while i < region_index_count { 100 let idx = region_indices.get(i)?; 101 delta += f32::from(s.read::<i8>()?) * self.regions.evaluate_region(idx, coordinates); 102 i += 1; 103 } 104 105 Some(delta) 106 } 107 } 108 109 110 #[derive(Clone, Copy)] 111 pub struct VariationRegionList<'a> { 112 axis_count: u16, 113 regions: LazyArray16<'a, RegionAxisCoordinatesRecord>, 114 } 115 116 impl<'a> VariationRegionList<'a> { 117 #[inline] evaluate_region( &self, index: u16, coordinates: &[NormalizedCoord], ) -> f32118 pub(crate) fn evaluate_region( 119 &self, 120 index: u16, 121 coordinates: &[NormalizedCoord], 122 ) -> f32 { 123 let mut v = 1.0; 124 for (i, coord) in coordinates.iter().enumerate() { 125 let region = match self.regions.get(index * self.axis_count + i as u16) { 126 Some(r) => r, 127 None => return 0.0, 128 }; 129 130 let factor = region.evaluate_axis(coord.get()); 131 if factor == 0.0 { 132 return 0.0; 133 } 134 135 v *= factor; 136 } 137 138 v 139 } 140 } 141 142 143 #[derive(Clone, Copy)] 144 struct RegionAxisCoordinatesRecord { 145 start_coord: i16, 146 peak_coord: i16, 147 end_coord: i16, 148 } 149 150 impl RegionAxisCoordinatesRecord { 151 #[inline] evaluate_axis(&self, coord: i16) -> f32152 pub fn evaluate_axis(&self, coord: i16) -> f32 { 153 let start = self.start_coord; 154 let peak = self.peak_coord; 155 let end = self.end_coord; 156 157 if start > peak || peak > end { 158 return 1.0; 159 } 160 161 if start < 0 && end > 0 && peak != 0 { 162 return 1.0; 163 } 164 165 if peak == 0 || coord == peak { 166 return 1.0; 167 } 168 169 if coord <= start || end <= coord { 170 return 0.0; 171 } 172 173 if coord < peak { 174 f32::from(coord - start) / f32::from(peak - start) 175 } else { 176 f32::from(end - coord) / f32::from(end - peak) 177 } 178 } 179 } 180 181 impl FromData for RegionAxisCoordinatesRecord { 182 const SIZE: usize = 6; 183 184 #[inline] parse(data: &[u8]) -> Option<Self>185 fn parse(data: &[u8]) -> Option<Self> { 186 let mut s = Stream::new(data); 187 Some(RegionAxisCoordinatesRecord { 188 start_coord: s.read()?, 189 peak_coord: s.read()?, 190 end_coord: s.read()?, 191 }) 192 } 193 } 194