/src/fontations/klippa/src/variations.rs
Line | Count | Source |
1 | | //! impl Subset for OpenType font variations common tables. |
2 | | use crate::{ |
3 | | inc_bimap::IncBiMap, |
4 | | offset::SerializeSubset, |
5 | | serialize::{SerializeErrorFlags, Serializer}, |
6 | | Plan, SubsetTable, |
7 | | }; |
8 | | use fnv::FnvHashMap; |
9 | | use write_fonts::{ |
10 | | read::{ |
11 | | collections::IntSet, |
12 | | tables::variations::{ |
13 | | DeltaSetIndexMap, ItemVariationData, ItemVariationStore, VariationRegionList, |
14 | | }, |
15 | | }, |
16 | | types::{BigEndian, F2Dot14, FixedSize, Offset32}, |
17 | | }; |
18 | | |
19 | | impl<'a> SubsetTable<'a> for ItemVariationStore<'a> { |
20 | | type ArgsForSubset = &'a [IncBiMap]; |
21 | | type Output = (); |
22 | | |
23 | 0 | fn subset( |
24 | 0 | &self, |
25 | 0 | plan: &Plan, |
26 | 0 | s: &mut Serializer, |
27 | 0 | inner_maps: &[IncBiMap], |
28 | 0 | ) -> Result<(), SerializeErrorFlags> { |
29 | 0 | if inner_maps.is_empty() { |
30 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_EMPTY); |
31 | 0 | } |
32 | 0 | s.embed(self.format())?; |
33 | | |
34 | 0 | let regions = self |
35 | 0 | .variation_region_list() |
36 | 0 | .map_err(|_| SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR)?; |
37 | | |
38 | 0 | let var_data_array = self.item_variation_data(); |
39 | 0 | let mut region_indices = IntSet::empty(); |
40 | 0 | for (i, inner_map) in inner_maps.iter().enumerate() { |
41 | 0 | match var_data_array.get(i) { |
42 | 0 | Some(Ok(var_data)) => { |
43 | 0 | collect_region_refs(&var_data, inner_map, &mut region_indices); |
44 | 0 | } |
45 | 0 | None => continue, |
46 | 0 | Some(Err(_e)) => { |
47 | 0 | return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR)); |
48 | | } |
49 | | } |
50 | | } |
51 | | |
52 | 0 | let max_region_count = regions.region_count(); |
53 | 0 | region_indices.remove_range(max_region_count..=u16::MAX); |
54 | | |
55 | 0 | if region_indices.is_empty() { |
56 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_EMPTY); |
57 | 0 | } |
58 | | |
59 | 0 | let mut region_map = IncBiMap::with_capacity(region_indices.len() as usize); |
60 | 0 | for region in region_indices.iter() { |
61 | 0 | region_map.add(region as u32); |
62 | 0 | } |
63 | | |
64 | 0 | let Ok(var_region_list) = self.variation_region_list() else { |
65 | 0 | return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR)); |
66 | | }; |
67 | | |
68 | | // var_region_list |
69 | 0 | let regions_offset_pos = s.embed(Offset32::new(0))?; |
70 | 0 | Offset32::serialize_subset(&var_region_list, s, plan, ®ion_map, regions_offset_pos)?; |
71 | | |
72 | 0 | serialize_var_data_offset_array(self, s, plan, inner_maps, ®ion_map) |
73 | 0 | } |
74 | | } |
75 | | |
76 | | impl<'a> SubsetTable<'a> for VariationRegionList<'a> { |
77 | | type ArgsForSubset = &'a IncBiMap; |
78 | | type Output = (); |
79 | | |
80 | 0 | fn subset( |
81 | 0 | &self, |
82 | 0 | _plan: &Plan, |
83 | 0 | s: &mut Serializer, |
84 | 0 | region_map: &IncBiMap, |
85 | 0 | ) -> Result<(), SerializeErrorFlags> { |
86 | 0 | let axis_count = self.axis_count(); |
87 | 0 | s.embed(axis_count)?; |
88 | | |
89 | 0 | let region_count = region_map.len() as u16; |
90 | 0 | s.embed(region_count)?; |
91 | | |
92 | | //Fixed size of a VariationRegion |
93 | 0 | let var_region_size = 3 * axis_count as usize * F2Dot14::RAW_BYTE_LEN; |
94 | 0 | if var_region_size.checked_mul(region_count as usize).is_none() { |
95 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER); |
96 | 0 | } |
97 | | |
98 | 0 | let subset_var_regions_size = var_region_size * region_count as usize; |
99 | 0 | let var_regions_pos = s.allocate_size(subset_var_regions_size, false)?; |
100 | | |
101 | 0 | let src_region_count = self.region_count() as u32; |
102 | 0 | let Some(src_var_regions_bytes) = self |
103 | 0 | .offset_data() |
104 | 0 | .as_bytes() |
105 | 0 | .get(self.shape().variation_regions_byte_range()) |
106 | | else { |
107 | 0 | return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR)); |
108 | | }; |
109 | | |
110 | 0 | for r in 0..region_count { |
111 | 0 | let Some(backward) = region_map.get_backward(r as u32) else { |
112 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER); |
113 | | }; |
114 | 0 | if *backward >= src_region_count { |
115 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER); |
116 | 0 | } |
117 | | |
118 | 0 | let src_pos = (*backward as usize) * var_region_size; |
119 | 0 | let Some(src_bytes) = src_var_regions_bytes.get(src_pos..src_pos + var_region_size) |
120 | | else { |
121 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER); |
122 | | }; |
123 | 0 | s.copy_assign_from_bytes(var_regions_pos + r as usize * var_region_size, src_bytes); |
124 | | } |
125 | 0 | Ok(()) |
126 | 0 | } |
127 | | } |
128 | | |
129 | 0 | fn serialize_var_data_offset_array( |
130 | 0 | var_store: &ItemVariationStore, |
131 | 0 | s: &mut Serializer, |
132 | 0 | plan: &Plan, |
133 | 0 | inner_maps: &[IncBiMap], |
134 | 0 | region_map: &IncBiMap, |
135 | 0 | ) -> Result<(), SerializeErrorFlags> { |
136 | 0 | let mut vardata_count = 0_u16; |
137 | 0 | let count_pos = s.embed(vardata_count)?; |
138 | | |
139 | 0 | let var_data_array = var_store.item_variation_data(); |
140 | 0 | for (i, inner_map) in inner_maps.iter().enumerate() { |
141 | 0 | if inner_map.len() == 0 { |
142 | 0 | continue; |
143 | 0 | } |
144 | 0 | match var_data_array.get(i) { |
145 | 0 | Some(Ok(var_data)) => { |
146 | 0 | let offset_pos = s.embed(0_u32)?; |
147 | 0 | Offset32::serialize_subset( |
148 | 0 | &var_data, |
149 | 0 | s, |
150 | 0 | plan, |
151 | 0 | (inner_map, region_map), |
152 | 0 | offset_pos, |
153 | 0 | )?; |
154 | 0 | vardata_count += 1; |
155 | | } |
156 | | _ => { |
157 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER); |
158 | | } |
159 | | } |
160 | | } |
161 | 0 | if vardata_count == 0 { |
162 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_EMPTY); |
163 | 0 | } |
164 | 0 | s.copy_assign(count_pos, vardata_count); |
165 | 0 | Ok(()) |
166 | 0 | } |
167 | | |
168 | | impl<'a> SubsetTable<'a> for ItemVariationData<'_> { |
169 | | type ArgsForSubset = (&'a IncBiMap, &'a IncBiMap); |
170 | | type Output = (); |
171 | | |
172 | 0 | fn subset( |
173 | 0 | &self, |
174 | 0 | _plan: &Plan, |
175 | 0 | s: &mut Serializer, |
176 | 0 | args: (&IncBiMap, &IncBiMap), |
177 | 0 | ) -> Result<(), SerializeErrorFlags> { |
178 | 0 | let (inner_map, region_map) = args; |
179 | 0 | let new_item_count = inner_map.len() as u16; |
180 | 0 | s.embed(new_item_count)?; |
181 | | |
182 | | // optimize word count |
183 | 0 | let ri_count = self.region_index_count() as usize; |
184 | | |
185 | | #[derive(Clone, Copy, PartialEq)] |
186 | | enum DeltaSize { |
187 | | Zero, |
188 | | NonWord, |
189 | | Word, |
190 | | } |
191 | | |
192 | 0 | let mut delta_sz = Vec::new(); |
193 | 0 | delta_sz.resize(ri_count, DeltaSize::Zero); |
194 | | // maps new index to old index |
195 | 0 | let mut ri_map = vec![0; ri_count]; |
196 | | |
197 | 0 | let mut new_word_count: u16 = 0; |
198 | | |
199 | 0 | let src_delta_bytes = self.delta_sets(); |
200 | 0 | let src_row_size = self.get_delta_row_len(); |
201 | | |
202 | 0 | let src_word_delta_count = self.word_delta_count(); |
203 | 0 | let src_word_count = (src_word_delta_count & 0x7FFF) as usize; |
204 | 0 | let src_long_words = src_word_count & 0x8000 != 0; |
205 | | |
206 | 0 | let mut has_long = false; |
207 | 0 | if src_long_words { |
208 | 0 | for r in 0..src_word_count { |
209 | 0 | for item in inner_map.keys() { |
210 | 0 | let delta = |
211 | 0 | get_item_delta(self, *item as usize, r, src_row_size, src_delta_bytes); |
212 | 0 | if !(-65536..=65535).contains(&delta) { |
213 | 0 | has_long = true; |
214 | 0 | break; |
215 | 0 | } |
216 | | } |
217 | | } |
218 | 0 | } |
219 | | |
220 | 0 | let min_threshold = if has_long { -65536 } else { -128 }; |
221 | 0 | let max_threshold = if has_long { 65535 } else { 127 }; |
222 | | |
223 | 0 | for (r, delta_size) in delta_sz.iter_mut().enumerate() { |
224 | 0 | let short_circuit = src_long_words == has_long && src_word_count <= r; |
225 | 0 | for item in inner_map.keys() { |
226 | 0 | let delta = get_item_delta(self, *item as usize, r, src_row_size, src_delta_bytes); |
227 | 0 | if delta < min_threshold || delta > max_threshold { |
228 | 0 | *delta_size = DeltaSize::Word; |
229 | 0 | new_word_count += 1; |
230 | 0 | break; |
231 | 0 | } else if delta != 0 { |
232 | 0 | *delta_size = DeltaSize::NonWord; |
233 | 0 | if short_circuit { |
234 | 0 | break; |
235 | 0 | } |
236 | 0 | } |
237 | | } |
238 | | } |
239 | | |
240 | 0 | let mut word_index: u16 = 0; |
241 | 0 | let mut non_word_index = new_word_count; |
242 | 0 | let mut new_ri_count: u16 = 0; |
243 | | |
244 | 0 | for (r, delta_type) in delta_sz.iter().enumerate() { |
245 | 0 | if *delta_type == DeltaSize::Zero { |
246 | 0 | continue; |
247 | 0 | } |
248 | | |
249 | 0 | if *delta_type == DeltaSize::Word { |
250 | 0 | let new_r = word_index as usize; |
251 | 0 | word_index += 1; |
252 | 0 | ri_map[new_r] = r; |
253 | 0 | } else { |
254 | 0 | let new_r = non_word_index as usize; |
255 | 0 | non_word_index += 1; |
256 | 0 | ri_map[new_r] = r; |
257 | 0 | } |
258 | 0 | new_ri_count += 1; |
259 | | } |
260 | | |
261 | 0 | let new_word_delta_count = if has_long { |
262 | 0 | new_word_count | 0x8000 |
263 | | } else { |
264 | 0 | new_word_count |
265 | | }; |
266 | 0 | s.embed(new_word_delta_count)?; |
267 | 0 | s.embed(new_ri_count)?; |
268 | | |
269 | 0 | let region_indices_pos = s.allocate_size(new_ri_count as usize * 2, false)?; |
270 | 0 | let src_region_indices = self.region_indexes(); |
271 | 0 | for (idx, src_idx) in ri_map.iter().enumerate().take(new_ri_count as usize) { |
272 | 0 | let Some(old_r) = src_region_indices.get(*src_idx) else { |
273 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER); |
274 | | }; |
275 | | |
276 | 0 | let Some(region) = region_map.get(old_r.get() as u32) else { |
277 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER); |
278 | | }; |
279 | 0 | s.copy_assign(region_indices_pos + idx * 2, *region as u16); |
280 | | } |
281 | | |
282 | 0 | let new_row_size = ItemVariationData::delta_row_len(new_word_delta_count, new_ri_count); |
283 | 0 | let new_delta_bytes_len = new_item_count as usize * new_row_size; |
284 | | |
285 | 0 | let delta_bytes_pos = s.allocate_size(new_delta_bytes_len, false)?; |
286 | 0 | for i in 0..new_item_count as usize { |
287 | 0 | let Some(old_i) = inner_map.get_backward(i as u32) else { |
288 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER); |
289 | | }; |
290 | | |
291 | 0 | let old_i = *old_i as usize; |
292 | 0 | for (r, old_r) in ri_map.iter().enumerate().take(new_ri_count as usize) { |
293 | 0 | set_item_delta( |
294 | 0 | s, |
295 | 0 | delta_bytes_pos, |
296 | 0 | i, |
297 | 0 | r, |
298 | 0 | get_item_delta(self, old_i, *old_r, src_row_size, src_delta_bytes), |
299 | 0 | new_row_size, |
300 | 0 | has_long, |
301 | 0 | new_word_count as usize, |
302 | 0 | )?; |
303 | | } |
304 | | } |
305 | | |
306 | 0 | Ok(()) |
307 | 0 | } |
308 | | } |
309 | | |
310 | 0 | fn get_item_delta( |
311 | 0 | var_data: &ItemVariationData, |
312 | 0 | item: usize, |
313 | 0 | region: usize, |
314 | 0 | row_size: usize, |
315 | 0 | delta_bytes: &[u8], |
316 | 0 | ) -> i32 { |
317 | 0 | if item >= var_data.item_count() as usize || region >= var_data.region_index_count() as usize { |
318 | 0 | return 0; |
319 | 0 | } |
320 | | |
321 | 0 | let p = item * row_size; |
322 | 0 | let word_delta_count = var_data.word_delta_count(); |
323 | 0 | let word_count = (word_delta_count & 0x7FFF) as usize; |
324 | 0 | let is_long = word_delta_count & 0x8000 != 0; |
325 | | |
326 | | // direct port from Harfbuzz: <https://github.com/harfbuzz/harfbuzz/blob/22fbc7568828b9acfd116be44b2d77d56d2d448b/src/hb-ot-layout-common.hh#L3061> |
327 | | // ignore the lint here |
328 | | #[allow(clippy::collapsible_else_if)] |
329 | 0 | if is_long { |
330 | 0 | if region < word_count { |
331 | 0 | let pos = p + region * 4; |
332 | 0 | let Some(delta_bytes) = delta_bytes.get(pos..pos + 4) else { |
333 | 0 | return 0; |
334 | | }; |
335 | 0 | BigEndian::<i32>::from_slice(delta_bytes).unwrap().get() |
336 | | } else { |
337 | 0 | let pos = p + 4 * word_count + 2 * (region - word_count); |
338 | 0 | let Some(delta_bytes) = delta_bytes.get(pos..pos + 2) else { |
339 | 0 | return 0; |
340 | | }; |
341 | 0 | BigEndian::<i16>::from_slice(delta_bytes).unwrap().get() as i32 |
342 | | } |
343 | | } else { |
344 | 0 | if region < word_count { |
345 | 0 | let pos = p + region * 2; |
346 | 0 | let Some(delta_bytes) = delta_bytes.get(pos..pos + 2) else { |
347 | 0 | return 0; |
348 | | }; |
349 | 0 | BigEndian::<i16>::from_slice(delta_bytes).unwrap().get() as i32 |
350 | | } else { |
351 | 0 | let pos = p + 2 * word_count + (region - word_count); |
352 | 0 | let Some(delta_bytes) = delta_bytes.get(pos..pos + 1) else { |
353 | 0 | return 0; |
354 | | }; |
355 | 0 | BigEndian::<i8>::from_slice(delta_bytes).unwrap().get() as i32 |
356 | | } |
357 | | } |
358 | 0 | } |
359 | | |
360 | | // direct port from Harfbuzz: <https://github.com/harfbuzz/harfbuzz/blob/22fbc7568828b9acfd116be44b2d77d56d2d448b/src/hb-ot-layout-common.hh#L3090> |
361 | | // ignore the lint here |
362 | | #[allow(clippy::too_many_arguments)] |
363 | 0 | fn set_item_delta( |
364 | 0 | s: &mut Serializer, |
365 | 0 | pos: usize, |
366 | 0 | item: usize, |
367 | 0 | region: usize, |
368 | 0 | delta: i32, |
369 | 0 | row_size: usize, |
370 | 0 | has_long: bool, |
371 | 0 | word_count: usize, |
372 | 0 | ) -> Result<(), SerializeErrorFlags> { |
373 | 0 | let p = pos + item * row_size; |
374 | | #[allow(clippy::collapsible_else_if)] |
375 | 0 | if has_long { |
376 | 0 | if region < word_count { |
377 | 0 | let pos = p + region * 4; |
378 | 0 | s.copy_assign(pos, delta); |
379 | 0 | } else { |
380 | 0 | let pos = p + 4 * word_count + 2 * (region - word_count); |
381 | 0 | let Ok(delta) = i16::try_from(delta) else { |
382 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER); |
383 | | }; |
384 | 0 | s.copy_assign(pos, delta); |
385 | | } |
386 | | } else { |
387 | 0 | if region < word_count { |
388 | 0 | let pos = p + region * 2; |
389 | 0 | let Ok(delta) = i16::try_from(delta) else { |
390 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER); |
391 | | }; |
392 | 0 | s.copy_assign(pos, delta); |
393 | | } else { |
394 | 0 | let pos = p + 2 * word_count + (region - word_count); |
395 | 0 | let Ok(delta) = i8::try_from(delta) else { |
396 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER); |
397 | | }; |
398 | 0 | s.copy_assign(pos, delta); |
399 | | } |
400 | | } |
401 | 0 | Ok(()) |
402 | 0 | } |
403 | | |
404 | 0 | fn collect_region_refs( |
405 | 0 | var_data: &ItemVariationData, |
406 | 0 | inner_map: &IncBiMap, |
407 | 0 | region_indices: &mut IntSet<u16>, |
408 | 0 | ) { |
409 | 0 | if inner_map.len() == 0 { |
410 | 0 | return; |
411 | 0 | } |
412 | 0 | let delta_bytes = var_data.delta_sets(); |
413 | 0 | let row_size = var_data.get_delta_row_len(); |
414 | | |
415 | 0 | let regions = var_data.region_indexes(); |
416 | 0 | for (i, region) in regions.iter().enumerate() { |
417 | 0 | let region = region.get(); |
418 | 0 | if region_indices.contains(region) { |
419 | 0 | continue; |
420 | 0 | } |
421 | | |
422 | 0 | for item in inner_map.keys() { |
423 | 0 | if get_item_delta(var_data, *item as usize, i, row_size, delta_bytes) != 0 { |
424 | 0 | region_indices.insert(region); |
425 | 0 | break; |
426 | 0 | } |
427 | | } |
428 | | } |
429 | 0 | } |
430 | | |
431 | | pub(crate) struct DeltaSetIndexMapSerializePlan<'a> { |
432 | | outer_bit_count: u8, |
433 | | inner_bit_count: u8, |
434 | | output_map: &'a FnvHashMap<u32, u32>, |
435 | | map_count: u32, |
436 | | } |
437 | | |
438 | | impl<'a> DeltaSetIndexMapSerializePlan<'a> { |
439 | 0 | pub(crate) fn new( |
440 | 0 | outer_bit_count: u8, |
441 | 0 | inner_bit_count: u8, |
442 | 0 | output_map: &'a FnvHashMap<u32, u32>, |
443 | 0 | map_count: u32, |
444 | 0 | ) -> Self { |
445 | 0 | Self { |
446 | 0 | outer_bit_count, |
447 | 0 | inner_bit_count, |
448 | 0 | output_map, |
449 | 0 | map_count, |
450 | 0 | } |
451 | 0 | } |
452 | | |
453 | 0 | pub(crate) fn width(&self) -> u8 { |
454 | 0 | (self.outer_bit_count + self.inner_bit_count).div_ceil(8) |
455 | 0 | } |
456 | | |
457 | 0 | pub(crate) fn inner_bit_count(&self) -> u8 { |
458 | 0 | self.inner_bit_count |
459 | 0 | } |
460 | | |
461 | 0 | pub(crate) fn output_map(&self) -> &'a FnvHashMap<u32, u32> { |
462 | 0 | self.output_map |
463 | 0 | } |
464 | | |
465 | 0 | pub(crate) fn map_count(&self) -> u32 { |
466 | 0 | self.map_count |
467 | 0 | } |
468 | | } |
469 | | |
470 | | impl<'a> SubsetTable<'a> for DeltaSetIndexMap<'a> { |
471 | | type ArgsForSubset = &'a DeltaSetIndexMapSerializePlan<'a>; |
472 | | type Output = (); |
473 | | |
474 | 0 | fn subset( |
475 | 0 | &self, |
476 | 0 | _plan: &Plan, |
477 | 0 | s: &mut Serializer, |
478 | 0 | index_map_subset_plan: &'a DeltaSetIndexMapSerializePlan<'a>, |
479 | 0 | ) -> Result<(), SerializeErrorFlags> { |
480 | 0 | let output_map = index_map_subset_plan.output_map(); |
481 | 0 | let width = index_map_subset_plan.width(); |
482 | 0 | let inner_bit_count = index_map_subset_plan.inner_bit_count(); |
483 | | |
484 | 0 | let map_count = index_map_subset_plan.map_count(); |
485 | | // sanity check |
486 | 0 | if map_count > 0 && (((inner_bit_count - 1) & (!0xF)) != 0 || (((width - 1) & (!0x3)) != 0)) |
487 | | { |
488 | 0 | return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER); |
489 | 0 | } |
490 | | |
491 | 0 | let format: u8 = if map_count <= 0xFFFF { 0 } else { 1 }; |
492 | 0 | s.embed(format)?; |
493 | | |
494 | 0 | let entry_format = ((width - 1) << 4) | (inner_bit_count - 1); |
495 | 0 | s.embed(entry_format)?; |
496 | | |
497 | 0 | if format == 0 { |
498 | 0 | s.embed(map_count as u16)?; |
499 | | } else { |
500 | 0 | s.embed(map_count)?; |
501 | | } |
502 | | |
503 | 0 | let num_data_bytes = width as usize * map_count as usize; |
504 | 0 | let mapdata_pos = s.allocate_size(num_data_bytes, true)?; |
505 | | |
506 | 0 | let be_byte_index_start = 4 - width as usize; |
507 | 0 | for i in 0..map_count { |
508 | 0 | let Some(v) = output_map.get(&i) else { |
509 | 0 | continue; |
510 | | }; |
511 | 0 | if *v == 0 { |
512 | 0 | continue; |
513 | 0 | } |
514 | | |
515 | 0 | let outer = v >> 16; |
516 | 0 | let inner = v & 0xFFFF; |
517 | 0 | let u = (outer << inner_bit_count) | inner; |
518 | 0 | let data_bytes = u.to_be_bytes(); |
519 | 0 | let data_pos = mapdata_pos + (i as usize) * width as usize; |
520 | 0 | s.copy_assign_from_bytes(data_pos, data_bytes.get(be_byte_index_start..4).unwrap()); |
521 | | } |
522 | | |
523 | 0 | Ok(()) |
524 | 0 | } |
525 | | } |
526 | | |
527 | | #[cfg(test)] |
528 | | mod test { |
529 | | use super::*; |
530 | | use skrifa::raw::{FontData, FontRead}; |
531 | | #[test] |
532 | | fn test_subset_item_varstore() { |
533 | | use crate::DEFAULT_LAYOUT_FEATURES; |
534 | | let raw_bytes: [u8; 471] = [ |
535 | | 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, |
536 | | 0x00, 0x6f, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x02, 0x00, 0x05, |
537 | | 0xc0, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
538 | | 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
539 | | 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0x00, 0x00, |
540 | | 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, |
541 | | 0x40, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xd8, 0xdd, |
542 | | 0xe2, 0xec, 0xf1, 0xf6, 0xfb, 0x05, 0x0a, 0x0f, 0x14, 0x1e, 0x28, 0x32, 0x3c, 0x00, |
543 | | 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x8d, 0xa1, 0xb5, 0xba, 0xbf, 0xc4, 0xce, |
544 | | 0xd8, 0xdd, 0xe2, 0xe7, 0xec, 0xf1, 0xf6, 0xfb, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1e, |
545 | | 0x28, 0x2d, 0x32, 0x3c, 0x46, 0x64, 0x00, 0x90, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, |
546 | | 0x00, 0x01, 0xba, 0xa1, 0xba, 0x14, 0xba, 0x32, 0xc4, 0xc4, 0xc4, 0xd8, 0xc4, 0xe2, |
547 | | 0xc4, 0x0a, 0xc4, 0x28, 0xce, 0xba, 0xce, 0xc4, 0xce, 0xd8, 0xce, 0xe2, 0xce, 0xec, |
548 | | 0xce, 0x28, 0xce, 0x32, 0xd8, 0x92, 0xd8, 0x9c, 0xd8, 0xbf, 0xd8, 0xce, 0xd8, 0xd8, |
549 | | 0xd8, 0xe2, 0xd8, 0xe7, 0xd8, 0xec, 0xd8, 0xf6, 0xd8, 0x1e, 0xe2, 0xc4, 0xe2, 0xce, |
550 | | 0xe2, 0xd8, 0xe2, 0xe2, 0xe2, 0xe7, 0xe2, 0xec, 0xe2, 0xf1, 0xe2, 0xf6, 0xe2, 0x0a, |
551 | | 0xe2, 0x14, 0xe2, 0x28, 0xe2, 0x32, 0xe2, 0x46, 0xec, 0xba, 0xec, 0xc4, 0xec, 0xce, |
552 | | 0xec, 0xd8, 0xec, 0xdd, 0xec, 0xe2, 0xec, 0xec, 0xec, 0xf1, 0xec, 0xf6, 0xec, 0xfb, |
553 | | 0xec, 0x05, 0xec, 0x0a, 0xec, 0x14, 0xec, 0x1e, 0xec, 0x28, 0xec, 0x32, 0xec, 0x50, |
554 | | 0xf1, 0xd3, 0xf1, 0xf6, 0xf1, 0xfb, 0xf6, 0xc4, 0xf6, 0xce, 0xf6, 0xd8, 0xf6, 0xe2, |
555 | | 0xf6, 0xe7, 0xf6, 0xec, 0xf6, 0xf1, 0xf6, 0xf6, 0xf6, 0xfb, 0xf6, 0x05, 0xf6, 0x0a, |
556 | | 0xf6, 0x14, 0xf6, 0x19, 0xf6, 0x1e, 0xf6, 0x28, 0xf6, 0x32, 0xf6, 0x3c, 0xf6, 0x50, |
557 | | 0xfb, 0xec, 0xfb, 0xf6, 0xfb, 0x05, 0xfb, 0x0a, 0xfb, 0x14, 0xfb, 0x19, 0xfb, 0x2d, |
558 | | 0xfb, 0x37, 0x05, 0xe7, 0x05, 0xec, 0x05, 0xf1, 0x05, 0xf6, 0x05, 0xfb, 0x05, 0x05, |
559 | | 0x05, 0x0a, 0x0a, 0xc9, 0x0a, 0xce, 0x0a, 0xd3, 0x0a, 0xd8, 0x0a, 0xe2, 0x0a, 0xec, |
560 | | 0x0a, 0xf1, 0x0a, 0xf6, 0x0a, 0xfb, 0x0a, 0x05, 0x0a, 0x0a, 0x0a, 0x0f, 0x0a, 0x14, |
561 | | 0x0a, 0x1e, 0x0a, 0x28, 0x0a, 0x32, 0x0a, 0x3c, 0x0a, 0x46, 0x0a, 0x50, 0x0f, 0xfb, |
562 | | 0x0f, 0x05, 0x0f, 0x0a, 0x0f, 0x0f, 0x14, 0xc4, 0x14, 0xce, 0x14, 0xd8, 0x14, 0xe2, |
563 | | 0x14, 0xec, 0x14, 0xf6, 0x14, 0x0a, 0x14, 0x0f, 0x14, 0x14, 0x14, 0x1e, 0x14, 0x28, |
564 | | 0x14, 0x32, 0x14, 0x3c, 0x14, 0x46, 0x1e, 0xec, 0x1e, 0xf6, 0x1e, 0xfb, 0x1e, 0x0a, |
565 | | 0x1e, 0x14, 0x1e, 0x1e, 0x1e, 0x28, 0x1e, 0x32, 0x1e, 0x3c, 0x28, 0xe2, 0x28, 0x0a, |
566 | | 0x28, 0x14, 0x28, 0x1e, 0x28, 0x28, 0x28, 0x32, 0x32, 0x14, 0x00, 0x05, 0x00, 0x00, |
567 | | 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0xe2, 0xf6, 0x1e, 0xe2, 0x00, 0x1e, |
568 | | 0xec, 0x00, 0x14, 0x00, 0x1e, 0x1e, 0x14, 0x1e, 0x0a, |
569 | | ]; |
570 | | |
571 | | let item_varstore = ItemVariationStore::read(FontData::new(&raw_bytes)).unwrap(); |
572 | | |
573 | | let mut plan = Plan::default(); |
574 | | // create inner maps |
575 | | let mut bimap = IncBiMap::with_capacity(1); |
576 | | bimap.add(10); |
577 | | plan.base_varstore_inner_maps.push(bimap); |
578 | | |
579 | | let mut bimap = IncBiMap::with_capacity(4); |
580 | | bimap.add(13); |
581 | | bimap.add(16); |
582 | | bimap.add(17); |
583 | | bimap.add(18); |
584 | | plan.base_varstore_inner_maps.push(bimap); |
585 | | |
586 | | let mut bimap = IncBiMap::with_capacity(3); |
587 | | bimap.add(100); |
588 | | bimap.add(101); |
589 | | bimap.add(122); |
590 | | plan.base_varstore_inner_maps.push(bimap); |
591 | | |
592 | | let bimap = IncBiMap::default(); |
593 | | plan.base_varstore_inner_maps.push(bimap); |
594 | | |
595 | | //layout_scripts |
596 | | plan.layout_scripts.invert(); |
597 | | |
598 | | //layout_features |
599 | | plan.layout_features |
600 | | .extend(DEFAULT_LAYOUT_FEATURES.iter().copied()); |
601 | | |
602 | | let mut s = Serializer::new(1024); |
603 | | assert_eq!(s.start_serialize(), Ok(())); |
604 | | let ret = item_varstore.subset(&plan, &mut s, &plan.base_varstore_inner_maps); |
605 | | assert_eq!(ret, Ok(())); |
606 | | assert!(!s.in_error()); |
607 | | s.end_serialize(); |
608 | | |
609 | | let subsetted_data = s.copy_bytes(); |
610 | | let expected_bytes: [u8; 85] = [ |
611 | | 0x00, 0x01, 0x00, 0x00, 0x00, 0x39, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, |
612 | | 0x00, 0x24, 0x00, 0x00, 0x00, 0x14, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, |
613 | | 0x00, 0x01, 0x0a, 0x05, 0x0a, 0x0a, 0x14, 0x14, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, |
614 | | 0x00, 0x01, 0xf6, 0x0a, 0x0f, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, |
615 | | 0x14, 0x00, 0x02, 0x00, 0x02, 0xc0, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
616 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
617 | | 0x00, |
618 | | ]; |
619 | | |
620 | | assert_eq!(subsetted_data, expected_bytes); |
621 | | } |
622 | | } |