diff --git a/font-codegen/src/fields.rs b/font-codegen/src/fields.rs index bd12826a9..b4bdad48e 100644 --- a/font-codegen/src/fields.rs +++ b/font-codegen/src/fields.rs @@ -157,7 +157,7 @@ impl Fields { .find(|fld| &fld.name == name) .map(|fld| match &fld.typ { FieldType::Scalar { typ } => typ, - _ => panic!("not a scalar field: {:?}", &fld.typ), + _ => panic!("not a scalar field"), }) .or_else(|| { self.read_args.as_ref().and_then(|args| { diff --git a/font-codegen/src/parsing.rs b/font-codegen/src/parsing.rs index 1b8fca9ce..7cc645e1d 100644 --- a/font-codegen/src/parsing.rs +++ b/font-codegen/src/parsing.rs @@ -319,7 +319,7 @@ pub(crate) enum CountTransform { /// requires exactly two args, defined as $arg1 - $arg2 + 2 SubAddTwo, /// requires exactly one arg. Get the count from the $arg1.try_into::(). - CustomCount, + Custom, } /// Attributes for specifying how to compile a field @@ -1470,7 +1470,7 @@ static TRANSFORM_IDENTS: &[(CountTransform, &str)] = &[ (CountTransform::BitmapLen, "bitmap_len"), (CountTransform::MaxValueBitmapLen, "max_value_bitmap_len"), (CountTransform::SubAddTwo, "subtract_add_two"), - (CountTransform::CustomCount, "custom"), + (CountTransform::Custom, "custom"), ]; impl FromStr for CountTransform { @@ -1508,7 +1508,7 @@ impl CountTransform { CountTransform::BitmapLen => 1, CountTransform::MaxValueBitmapLen => 1, CountTransform::SubAddTwo => 2, - CountTransform::CustomCount => 1, + CountTransform::Custom => 1, } } } @@ -1666,7 +1666,7 @@ impl Count { (CountTransform::SubAddTwo, [a, b]) => { quote!(transforms::subtract_add_two(#a, #b)) } - (CountTransform::CustomCount, [a]) => { + (CountTransform::Custom, [a]) => { quote!(transforms::custom_count(#a)) } _ => unreachable!("validated before now"), diff --git a/font-test-data/src/ift.rs b/font-test-data/src/ift.rs index 1eefed5d8..5f1c4ee29 100644 --- a/font-test-data/src/ift.rs +++ b/font-test-data/src/ift.rs @@ -296,7 +296,7 @@ pub fn features_and_design_space_format2() -> BeBuffer { buffer } -pub fn copy_indices_format2() -> BeBuffer { +pub fn child_indices_format2() -> BeBuffer { let mut buffer = be_buffer! { 2u8, // format @@ -347,33 +347,33 @@ pub fn copy_indices_format2() -> BeBuffer { 0x0064_0000, // end = 100 // Entry id = 5 - {0b00000010u8: "entries[4]"}, // format = COPY_INDICES - 1u8, // copy count - (Uint24::new(0)), // copy + {0b00000010u8: "entries[4]"}, // format = CHILD_INDICES + 1u8, // child count + (Uint24::new(0)), // child[0] = 0 // Entry id = 6 - {0b00000010u8: "entries[5]"}, // format = COPY_INDICES - 1u8, // copy count - (Uint24::new(2)), // copy + {0b00000010u8: "entries[5]"}, // format = CHILD_INDICES + 1u8, // child count + (Uint24::new(2)), // child // Entry id = 7 - {0b00000010u8: "entries[6]"}, // format = COPY_INDICES - 4u8, // copy count - (Uint24::new(3)), // copy[0] - (Uint24::new(2)), // copy[1] - (Uint24::new(1)), // copy[2] - (Uint24::new(0)), // copy[3] + {0b00000010u8: "entries[6]"}, // format = CHILD_INDICES + {4u8: "entries[6]_child_count"}, // child count + (Uint24::new(3)), // child[0] = 3 + (Uint24::new(2)), // child[1] = 2 + (Uint24::new(1)), // child[2] = 1 + (Uint24::new(0)), // child[3] = 0 // Entry id = 8 - {0b00000010u8: "entries[7]"}, // format = COPY_INDICES - 2u8, // copy count - (Uint24::new(4)), // copy[0] - (Uint24::new(5)), // copy[1] + {0b00000010u8: "entries[7]"}, // format = CHILD_INDICES + 2u8, // child count + (Uint24::new(4)), // child[0] = 4 + (Uint24::new(5)), // child[1] = 5 // Entry id = 9 - {0b00100010u8: "entries[8]"}, // format = CODEPOINT_BIT_2 | COPY_INDICES - 1u8, // copy count - (Uint24::new(0)), // copy[0] + {0b00100010u8: "entries[8]"}, // format = CODEPOINT_BIT_2 | CHILD_INDICES + 1u8, // child count + (Uint24::new(0)), // chil[0] = 0 100u16, // bias [0b00001101, 0b00000011, 0b00110001u8] // codepoints = [100..117] }; diff --git a/incremental-font-transfer/src/patch_group.rs b/incremental-font-transfer/src/patch_group.rs index 705d65919..6ff7ec203 100644 --- a/incremental-font-transfer/src/patch_group.rs +++ b/incremental-font-transfer/src/patch_group.rs @@ -1446,7 +1446,7 @@ mod tests { let s = SubsetDefinition::codepoints([5].into_iter().collect()); let g = PatchGroup::select_next_patches(font.clone(), &s); - assert!(g.is_err()); + assert!(g.is_err(), "did not fail as expected."); if let Err(err) = g { assert_eq!(ReadError::ValidationError, err); } diff --git a/incremental-font-transfer/src/patchmap.rs b/incremental-font-transfer/src/patchmap.rs index 6d6ea537a..522115213 100644 --- a/incremental-font-transfer/src/patchmap.rs +++ b/incremental-font-transfer/src/patchmap.rs @@ -358,6 +358,56 @@ fn merge_intersecting_entries( } } +struct EntryIntersectionCache<'a> { + entries: &'a [Entry], + cache: HashMap, +} + +impl<'a> EntryIntersectionCache<'a> { + fn intersects(&mut self, index: usize, subset_definition: &SubsetDefinition) -> bool { + if let Some(result) = self.cache.get(&index) { + return *result; + } + + let Some(entry) = self.entries.get(index) else { + return false; + }; + + let result = self.compute_intersection(entry, subset_definition); + self.cache.insert(index, result); + result + } + + fn compute_intersection( + &mut self, + entry: &Entry, + subset_definition: &SubsetDefinition, + ) -> bool { + // See: https://w3c.github.io/IFT/Overview.html#abstract-opdef-check-entry-intersection + if !entry.intersects(subset_definition) { + return false; + } + + if entry.child_indices.is_empty() { + return true; + } + + let mut some_match = false; + let mut all_match = true; + for child_index in entry.child_indices.iter() { + let child_intersects = self.intersects(*child_index, subset_definition); + some_match = some_match || child_intersects; + all_match = all_match && child_intersects; + } + + if entry.conjunctive_child_match { + all_match + } else { + some_match + } + } +} + fn add_intersecting_format2_patches( source_table: &IftTableTag, map: &PatchMapFormat2, @@ -366,25 +416,32 @@ fn add_intersecting_format2_patches( ) -> Result<(), ReadError> { let entries = decode_format2_entries(source_table, map)?; - for (order, mut e) in entries.into_iter().enumerate() { + // Caches the result of intersection check for an entry index. + let mut entry_intersection_cache = EntryIntersectionCache { + entries: &entries, + cache: Default::default(), + }; + + for (order, e) in entries.iter().enumerate() { if e.ignored { continue; } - if !e.intersects(subset_definition) { + if !entry_intersection_cache.intersects(order, subset_definition) { continue; } - if e.uri.encoding().is_invalidating() { + let mut uri = e.uri.clone(); + if uri.encoding().is_invalidating() { // for invalidating keyed patches we need to record information about intersection size to use later // for patch selection. - e.uri.intersection_info = IntersectionInfo::from_subset( + uri.intersection_info = IntersectionInfo::from_subset( e.subset_definition.intersection(subset_definition), order, ); } - patches.push(e.uri) + patches.push(uri) } Ok(()) @@ -460,8 +517,20 @@ fn decode_format2_entry<'a>( } // Copy indices - if let Some(copy_indices) = entry_data.copy_indices() { - // TODO XXXXXXX + if let (Some(child_indices), Some(match_mode)) = ( + entry_data.child_indices(), + entry_data.match_mode_and_count(), + ) { + let max_index = entries.len(); + for i in entry.child_indices.iter() { + if *i >= max_index { + return Err(ReadError::MalformedData( + "Child index must refer to only prior entries.", + )); + } + } + entry.child_indices = child_indices.iter().map(|v| v.get().into()).collect(); + entry.conjunctive_child_match = match_mode.conjunctive_match(); } // Design space @@ -483,19 +552,6 @@ fn decode_format2_entry<'a>( entry.subset_definition.design_space = DesignSpace::Ranges(ranges); } - // Copy Indices - if let Some(copy_indices) = entry_data.copy_indices() { - for index in copy_indices { - let entry_to_copy = - entries - .get(index.get().to_u32() as usize) - .ok_or(ReadError::MalformedData( - "copy index can only refer to a previous entry.", - ))?; - entry.union(entry_to_copy); - } - } - // Entry ID entry.uri.id = format2_new_entry_id(&entry_data, entries.last(), id_string_data)?; @@ -1072,8 +1128,8 @@ impl SubsetDefinition { struct Entry { // Key subset_definition: SubsetDefinition, - copy_indices: Vec, - append_mode: bool, + child_indices: Vec, + conjunctive_child_match: bool, ignored: bool, // Value @@ -1094,8 +1150,8 @@ impl Entry { design_space: Default::default(), }, - copy_indices: Default::default(), - append_mode: false, + child_indices: Default::default(), + conjunctive_child_match: false, ignored: false, uri: PatchUri::from_index( @@ -1162,12 +1218,6 @@ impl Entry { false } - - /// Union in the subset definition (codepoints, features, and design space segments) - /// from other. - fn union(&mut self, other: &Entry) { - self.subset_definition.union(&other.subset_definition); - } } #[cfg(test)] @@ -1175,7 +1225,7 @@ mod tests { use super::*; use font_test_data as test_data; use font_test_data::ift::{ - codepoints_only_format2, copy_indices_format2, custom_ids_format2, feature_map_format1, + child_indices_format2, codepoints_only_format2, custom_ids_format2, feature_map_format1, features_and_design_space_format2, simple_format1, string_ids_format2, u16_entries_format1, }; use read_fonts::tables::ift::{IFTX_TAG, IFT_TAG}; @@ -2294,23 +2344,24 @@ mod tests { } #[test] - fn format_2_patch_map_copy_indices() { + fn format_2_patch_map_disjunctive_child_indices() { let font_bytes = create_ift_font( FontRef::new(test_data::ift::IFT_BASE).unwrap(), - Some(©_indices_format2()), + Some(&child_indices_format2()), None, ); let font = FontRef::new(&font_bytes).unwrap(); - let e3 = f2(3, copy_indices_format2().offset_for("entries[2]")); - let e5 = f2(5, copy_indices_format2().offset_for("entries[4]")); - let e6 = f2(6, copy_indices_format2().offset_for("entries[5]")); - let e7 = f2(7, copy_indices_format2().offset_for("entries[6]")); - let e8 = f2(8, copy_indices_format2().offset_for("entries[7]")); - let e9 = f2(9, copy_indices_format2().offset_for("entries[8]")); + let e3 = f2(3, child_indices_format2().offset_for("entries[2]")); + let e5 = f2(5, child_indices_format2().offset_for("entries[4]")); + let e6 = f2(6, child_indices_format2().offset_for("entries[5]")); + let e7 = f2(7, child_indices_format2().offset_for("entries[6]")); + let e8 = f2(8, child_indices_format2().offset_for("entries[7]")); + let e9 = f2(9, child_indices_format2().offset_for("entries[8]")); test_intersection(&font, [], [], []); - test_intersection(&font, [0x05], [], [e5, e9]); - test_intersection(&font, [0x65], [], [e9]); + test_intersection(&font, [0x05], [], [e5, e7, e8]); + test_intersection(&font, [0x65], [], []); + test_intersection(&font, [0x05, 0x65], [], [e5, e7, e8, e9]); test_design_space_intersection( &font, @@ -2322,7 +2373,7 @@ mod tests { .into_iter() .collect(), )]), - [e3, e6], + [e3, e6, e7, e8], ); test_design_space_intersection( @@ -2335,7 +2386,44 @@ mod tests { .into_iter() .collect(), )]), - [e3, e5, e6, e7, e8, e9], + [e3, e5, e6, e7, e8], + ); + } + + #[test] + fn format_2_patch_map_conjunctive_child_indices() { + let mut builder = child_indices_format2(); + builder.write_at("entries[6]_child_count", 0b10000000u8 | 4u8); + + let font_bytes = create_ift_font( + FontRef::new(test_data::ift::IFT_BASE).unwrap(), + Some(&builder), + None, + ); + let font = FontRef::new(&font_bytes).unwrap(); + + let e2 = f2(2, child_indices_format2().offset_for("entries[1]")); + let e3 = f2(3, child_indices_format2().offset_for("entries[2]")); + let e4 = f2(4, child_indices_format2().offset_for("entries[3]")); + let e5 = f2(5, child_indices_format2().offset_for("entries[4]")); + let e6 = f2(6, child_indices_format2().offset_for("entries[5]")); + let e7 = f2(7, child_indices_format2().offset_for("entries[6]")); + let e8 = f2(8, child_indices_format2().offset_for("entries[7]")); + test_intersection(&font, [0x05], [], [e5, e8]); + test_design_space_intersection( + &font, + [0x05, 51], + FeatureSet::from([Tag::new(b"liga"), Tag::new(b"rlig")]), + DesignSpace::from([( + Tag::new(b"wght"), + [ + Fixed::from_i32(75)..=Fixed::from_i32(75), + Fixed::from_i32(500)..=Fixed::from_i32(500), + ] + .into_iter() + .collect(), + )]), + [e2, e3, e4, e5, e6, e7, e8], ); } @@ -2652,15 +2740,15 @@ mod tests { subset_definition: s1.clone(), uri: uri.clone(), ignored: false, - copy_indices: Default::default(), - append_mode: Default::default(), + child_indices: Default::default(), + conjunctive_child_match: Default::default(), }; let e2 = Entry { subset_definition: Default::default(), uri: uri.clone(), ignored: false, - copy_indices: Default::default(), - append_mode: Default::default(), + child_indices: Default::default(), + conjunctive_child_match: Default::default(), }; assert!(e1.intersects(&s1)); @@ -2768,15 +2856,15 @@ mod tests { subset_definition: s1.clone(), uri: uri.clone(), ignored: false, - copy_indices: Default::default(), - append_mode: Default::default(), + child_indices: Default::default(), + conjunctive_child_match: Default::default(), }; let e2 = Entry { subset_definition: Default::default(), uri: uri.clone(), ignored: false, - copy_indices: Default::default(), - append_mode: Default::default(), + child_indices: Default::default(), + conjunctive_child_match: Default::default(), }; assert!(e1.intersects(&s1)); @@ -2794,4 +2882,10 @@ mod tests { SubsetDefinition::default() ); } + + // TODO test for child indices: + // - detects invalid indices + // - conjunctive matching + // - disjunctive matching + // - multi level matching } diff --git a/read-fonts/generated/generated_ift.rs b/read-fonts/generated/generated_ift.rs index 904678e3f..97ba138e1 100644 --- a/read-fonts/generated/generated_ift.rs +++ b/read-fonts/generated/generated_ift.rs @@ -985,9 +985,9 @@ pub struct EntryDataMarker { design_space_count_byte_start: Option, design_space_segments_byte_start: Option, design_space_segments_byte_len: Option, - copy_mode_and_count_byte_start: Option, - copy_indices_byte_start: Option, - copy_indices_byte_len: Option, + match_mode_and_count_byte_start: Option, + child_indices_byte_start: Option, + child_indices_byte_len: Option, entry_id_delta_byte_start: Option, entry_id_delta_byte_len: Option, patch_format_byte_start: Option, @@ -1020,14 +1020,14 @@ impl EntryDataMarker { Some(start..start + self.design_space_segments_byte_len?) } - pub fn copy_mode_and_count_byte_range(&self) -> Option> { - let start = self.copy_mode_and_count_byte_start?; - Some(start..start + CopyModeAndCount::RAW_BYTE_LEN) + pub fn match_mode_and_count_byte_range(&self) -> Option> { + let start = self.match_mode_and_count_byte_start?; + Some(start..start + MatchModeAndCount::RAW_BYTE_LEN) } - pub fn copy_indices_byte_range(&self) -> Option> { - let start = self.copy_indices_byte_start?; - Some(start..start + self.copy_indices_byte_len?) + pub fn child_indices_byte_range(&self) -> Option> { + let start = self.child_indices_byte_start?; + Some(start..start + self.child_indices_byte_len?) } pub fn entry_id_delta_byte_range(&self) -> Option> { @@ -1041,7 +1041,7 @@ impl EntryDataMarker { } pub fn codepoint_data_byte_range(&self) -> Range { - let start = self . patch_format_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . entry_id_delta_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . copy_indices_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . copy_mode_and_count_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . design_space_segments_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . design_space_count_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . feature_tags_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . feature_count_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . format_flags_byte_range () . end)))))))) ; + let start = self . patch_format_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . entry_id_delta_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . child_indices_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . match_mode_and_count_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . design_space_segments_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . design_space_count_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . feature_tags_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . feature_count_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . format_flags_byte_range () . end)))))))) ; start..start + self.codepoint_data_byte_len } } @@ -1107,27 +1107,27 @@ impl<'a> FontReadWithArgs<'a> for EntryData<'a> { if let Some(value) = design_space_segments_byte_len { cursor.advance_by(value); } - let copy_mode_and_count_byte_start = format_flags - .contains(EntryFormatFlags::COPY_INDICES) + let match_mode_and_count_byte_start = format_flags + .contains(EntryFormatFlags::CHILD_INDICES) .then(|| cursor.position()) .transpose()?; - let copy_mode_and_count = format_flags - .contains(EntryFormatFlags::COPY_INDICES) - .then(|| cursor.read::()) + let match_mode_and_count = format_flags + .contains(EntryFormatFlags::CHILD_INDICES) + .then(|| cursor.read::()) .transpose()? .unwrap_or(Default::default()); - let copy_indices_byte_start = format_flags - .contains(EntryFormatFlags::COPY_INDICES) + let child_indices_byte_start = format_flags + .contains(EntryFormatFlags::CHILD_INDICES) .then(|| cursor.position()) .transpose()?; - let copy_indices_byte_len = format_flags - .contains(EntryFormatFlags::COPY_INDICES) + let child_indices_byte_len = format_flags + .contains(EntryFormatFlags::CHILD_INDICES) .then_some( - (transforms::custom_count(copy_mode_and_count)) + (transforms::custom_count(match_mode_and_count)) .checked_mul(Uint24::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?, ); - if let Some(value) = copy_indices_byte_len { + if let Some(value) = child_indices_byte_len { cursor.advance_by(value); } let entry_id_delta_byte_start = format_flags @@ -1160,9 +1160,9 @@ impl<'a> FontReadWithArgs<'a> for EntryData<'a> { design_space_count_byte_start, design_space_segments_byte_start, design_space_segments_byte_len, - copy_mode_and_count_byte_start, - copy_indices_byte_start, - copy_indices_byte_len, + match_mode_and_count_byte_start, + child_indices_byte_start, + child_indices_byte_len, entry_id_delta_byte_start, entry_id_delta_byte_len, patch_format_byte_start, @@ -1214,13 +1214,13 @@ impl<'a> EntryData<'a> { Some(self.data.read_array(range).unwrap()) } - pub fn copy_mode_and_count(&self) -> Option { - let range = self.shape.copy_mode_and_count_byte_range()?; + pub fn match_mode_and_count(&self) -> Option { + let range = self.shape.match_mode_and_count_byte_range()?; Some(self.data.read_at(range.start).unwrap()) } - pub fn copy_indices(&self) -> Option<&'a [BigEndian]> { - let range = self.shape.copy_indices_byte_range()?; + pub fn child_indices(&self) -> Option<&'a [BigEndian]> { + let range = self.shape.child_indices_byte_range()?; Some(self.data.read_array(range).unwrap()) } @@ -1276,12 +1276,12 @@ impl<'a> SomeTable<'a> for EntryData<'a> { ), )) } - 5usize if format_flags.contains(EntryFormatFlags::COPY_INDICES) => Some(Field::new( - "copy_mode_and_count", + 5usize if format_flags.contains(EntryFormatFlags::CHILD_INDICES) => Some(Field::new( + "match_mode_and_count", traversal::FieldType::Unknown, )), - 6usize if format_flags.contains(EntryFormatFlags::COPY_INDICES) => { - Some(Field::new("copy_indices", self.copy_indices().unwrap())) + 6usize if format_flags.contains(EntryFormatFlags::CHILD_INDICES) => { + Some(Field::new("child_indices", self.child_indices().unwrap())) } 7usize if format_flags.contains(EntryFormatFlags::ENTRY_ID_DELTA) => { Some(Field::new("entry_id_delta", traversal::FieldType::Unknown)) @@ -1313,7 +1313,7 @@ pub struct EntryFormatFlags { impl EntryFormatFlags { pub const FEATURES_AND_DESIGN_SPACE: Self = Self { bits: 0b00000001 }; - pub const COPY_INDICES: Self = Self { bits: 0b00000010 }; + pub const CHILD_INDICES: Self = Self { bits: 0b00000010 }; pub const ENTRY_ID_DELTA: Self = Self { bits: 0b00000100 }; @@ -1340,7 +1340,7 @@ impl EntryFormatFlags { pub const fn all() -> Self { Self { bits: Self::FEATURES_AND_DESIGN_SPACE.bits - | Self::COPY_INDICES.bits + | Self::CHILD_INDICES.bits | Self::ENTRY_ID_DELTA.bits | Self::PATCH_FORMAT.bits | Self::CODEPOINTS_BIT_1.bits @@ -1566,7 +1566,7 @@ impl std::fmt::Debug for EntryFormatFlags { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let members: &[(&str, Self)] = &[ ("FEATURES_AND_DESIGN_SPACE", Self::FEATURES_AND_DESIGN_SPACE), - ("COPY_INDICES", Self::COPY_INDICES), + ("CHILD_INDICES", Self::CHILD_INDICES), ("ENTRY_ID_DELTA", Self::ENTRY_ID_DELTA), ("PATCH_FORMAT", Self::PATCH_FORMAT), ("CODEPOINTS_BIT_1", Self::CODEPOINTS_BIT_1), diff --git a/read-fonts/src/tables/ift.rs b/read-fonts/src/tables/ift.rs index 48ef12aeb..34dec6bee 100644 --- a/read-fonts/src/tables/ift.rs +++ b/read-fonts/src/tables/ift.rs @@ -8,13 +8,13 @@ pub const IFT_TAG: types::Tag = Tag::new(b"IFT "); pub const IFTX_TAG: types::Tag = Tag::new(b"IFTX"); #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct CopyModeAndCount(u8); +pub struct MatchModeAndCount(u8); -impl CopyModeAndCount { +impl MatchModeAndCount { /// Flag indicating that copy mode is append. /// /// See: https://w3c.github.io/IFT/Overview.html#mapping-entry-copymodeandcount - pub const APPEND_MODE_MASK: u8 = 0b10000000; + pub const MATCH_MODE_MASK: u8 = 0b10000000; /// Mask for the low 7 bits to give the copy index count. pub const COUNT_MASK: u8 = 0b01111111; @@ -27,9 +27,9 @@ impl CopyModeAndCount { Self(bits) } - /// `true` if any tables reference a shared set of point numbers - pub fn append_mode(self) -> bool { - (self.0 & Self::APPEND_MODE_MASK) != 0 + /// If true matching mode is conjunctive (... AND ...) otherwise disjunctive (... OR ...) + pub fn conjunctive_match(self) -> bool { + (self.0 & Self::MATCH_MODE_MASK) != 0 } pub fn count(self) -> u8 { @@ -37,7 +37,7 @@ impl CopyModeAndCount { } } -impl TryInto for CopyModeAndCount { +impl TryInto for MatchModeAndCount { type Error = ReadError; fn try_into(self) -> Result { @@ -45,7 +45,7 @@ impl TryInto for CopyModeAndCount { } } -impl types::Scalar for CopyModeAndCount { +impl types::Scalar for MatchModeAndCount { type Raw = ::Raw; fn to_raw(self) -> Self::Raw { self.0.to_raw() diff --git a/resources/codegen_inputs/ift.rs b/resources/codegen_inputs/ift.rs index 0551050ec..dbe7a0c7f 100644 --- a/resources/codegen_inputs/ift.rs +++ b/resources/codegen_inputs/ift.rs @@ -1,6 +1,6 @@ #![parse_module(read_fonts::tables::ift)] -extern scalar CopyModeAndCount; +extern scalar MatchModeAndCount; extern record U8Or16; extern record U16Or24; extern record IdDeltaOrLength; @@ -161,14 +161,14 @@ table EntryData { #[count($design_space_count)] design_space_segments: [DesignSpaceSegment], - // COPY_INDICES - #[if_flag($format_flags, EntryFormatFlags::COPY_INDICES)] + // CHILD_INDICES + #[if_flag($format_flags, EntryFormatFlags::CHILD_INDICES)] #[traverse_with(skip)] #[compile(skip)] // TODO remove this once write fonts side is implemented.] - copy_mode_and_count: CopyModeAndCount, - #[if_flag($format_flags, EntryFormatFlags::COPY_INDICES)] - #[count(custom($copy_mode_and_count))] - copy_indices: [Uint24], + match_mode_and_count: MatchModeAndCount, + #[if_flag($format_flags, EntryFormatFlags::CHILD_INDICES)] + #[count(custom($match_mode_and_count))] + child_indices: [Uint24], // ENTRY_ID_DELTA #[read_with($entry_id_string_data_offset)] @@ -193,7 +193,7 @@ flags u8 EntryFormatFlags { FEATURES_AND_DESIGN_SPACE = 0b00000001, // Fields specifying copy indices are present. - COPY_INDICES = 0b00000010, + CHILD_INDICES = 0b00000010, // Fields specifying the entry ID delta are present. ENTRY_ID_DELTA = 0b00000100, diff --git a/write-fonts/generated/generated_ift.rs b/write-fonts/generated/generated_ift.rs index 498182e42..12d475e88 100644 --- a/write-fonts/generated/generated_ift.rs +++ b/write-fonts/generated/generated_ift.rs @@ -546,7 +546,7 @@ pub struct EntryData { pub feature_tags: Option>, pub design_space_count: Option, pub design_space_segments: Option>, - pub copy_indices: Option>, + pub child_indices: Option>, pub patch_format: Option, pub codepoint_data: Vec, } @@ -599,9 +599,9 @@ impl FontWrite for EntryData { .write_into(writer) }); self.format_flags - .contains(EntryFormatFlags::COPY_INDICES) + .contains(EntryFormatFlags::CHILD_INDICES) .then(|| { - self.copy_indices + self.child_indices .as_ref() .expect("missing conditional field should have failed validation") .write_into(writer) @@ -690,16 +690,16 @@ impl Validate for EntryData { } self.design_space_segments.validate_impl(ctx); }); - ctx.in_field("copy_indices", |ctx| { - if !(format_flags.contains(EntryFormatFlags::COPY_INDICES)) - && self.copy_indices.is_some() + ctx.in_field("child_indices", |ctx| { + if !(format_flags.contains(EntryFormatFlags::CHILD_INDICES)) + && self.child_indices.is_some() { - ctx.report("'copy_indices' is present but COPY_INDICES not set") + ctx.report("'child_indices' is present but CHILD_INDICES not set") } - if (format_flags.contains(EntryFormatFlags::COPY_INDICES)) - && self.copy_indices.is_none() + if (format_flags.contains(EntryFormatFlags::CHILD_INDICES)) + && self.child_indices.is_none() { - ctx.report("COPY_INDICES is set but 'copy_indices' is None") + ctx.report("CHILD_INDICES is set but 'child_indices' is None") } }); ctx.in_field("patch_format", |ctx| { @@ -727,7 +727,7 @@ impl<'a> FromObjRef> for EntryData { feature_tags: obj.feature_tags().to_owned_obj(offset_data), design_space_count: obj.design_space_count(), design_space_segments: obj.design_space_segments().to_owned_obj(offset_data), - copy_indices: obj.copy_indices().to_owned_obj(offset_data), + child_indices: obj.child_indices().to_owned_obj(offset_data), patch_format: obj.patch_format(), codepoint_data: obj.codepoint_data().to_owned_obj(offset_data), }