From 1a9a31fc3b3cbc2c5cd578e7fdc8704282d86d21 Mon Sep 17 00:00:00 2001 From: Chad Brokaw Date: Wed, 23 Aug 2023 16:21:12 -0400 Subject: [PATCH 1/5] Capture overlap bits from TrueType glyphs First step in addressing #581. Captures simple and composite overlap bits and plumbs them through internally. Still needs to be exposed in skrifa public API. This will be done in a follow up. --- .../test_data/ttf/vazirmatn_var_trimmed.ttf | Bin 1196 -> 1196 bytes .../test_data/ttx/vazirmatn_var_trimmed.ttx | 4 +- read-fonts/src/tables/glyf.rs | 73 ++++++++++++++++-- skrifa/src/scale/glyf/glyph.rs | 2 + skrifa/src/scale/glyf/mem.rs | 2 + skrifa/src/scale/glyf/scaler.rs | 23 +++++- 6 files changed, 94 insertions(+), 10 deletions(-) diff --git a/font-test-data/test_data/ttf/vazirmatn_var_trimmed.ttf b/font-test-data/test_data/ttf/vazirmatn_var_trimmed.ttf index 1f328116e856f7461e62a471bc1882b8c3c03aab..5ae539ddbd3d9c1197c9ccb8c8b4273b592edb99 100644 GIT binary patch delta 93 zcmZ3(xrTE>fy$zc^l%0S#sdrt3~lLUiAA^L*DPjWVEzE)@5)F`Oc8sQ*gSDcg3O$+ uF+1b=ZN4(_a{#3n7%tZS{Q{yN@`%T77GPvyWMrKz%B0BXxY?YklnDUK930XB delta 93 zcmZ3(xrTE>fy%rL^>79T#sdrt3~lLUiAA^L*DPjWVEzE)@5)F`Oc9Nmv1;O!1eq1Q udD-#&HeVU|Ie=0O3>RzvegV<<8~j=}3ox=UGBQpUWm05h+-%NN$^-z2x*O8~ diff --git a/font-test-data/test_data/ttx/vazirmatn_var_trimmed.ttx b/font-test-data/test_data/ttx/vazirmatn_var_trimmed.ttx index 90936e60c..f9ff9c893 100644 --- a/font-test-data/test_data/ttx/vazirmatn_var_trimmed.ttx +++ b/font-test-data/test_data/ttx/vazirmatn_var_trimmed.ttx @@ -126,7 +126,7 @@ and is intended to contain examples of many variable font tables --> - + PUSHB[ ] /* 2 values pushed */ @@ -142,7 +142,7 @@ and is intended to contain examples of many variable font tables --> - + diff --git a/read-fonts/src/tables/glyf.rs b/read-fonts/src/tables/glyf.rs index d7560903b..23d38a4d0 100644 --- a/read-fonts/src/tables/glyf.rs +++ b/read-fonts/src/tables/glyf.rs @@ -145,6 +145,17 @@ impl<'a> SimpleGlyph<'a> { .unwrap_or(0) } + /// Returns true if the contours in the simple glyph may overlap. + pub fn has_overlapping_contours(&self) -> bool { + // Checks the first flag for the OVERLAP_SIMPLE bit. + // Spec says: "When used, it must be set on the first flag byte for + // the glyph." + FontData::new(self.glyph_data()) + .read_at::(0) + .map(|flag| flag.contains(SimpleGlyphFlags::OVERLAP_SIMPLE)) + .unwrap_or_default() + } + /// Reads points and flags into the provided buffers. /// /// Drops all flag bits except on-curve. The lengths of the buffers must be @@ -479,8 +490,10 @@ impl<'a> CompositeGlyph<'a> { /// Returns an iterator that yields the glyph identifier of each component /// in the composite glyph. - pub fn component_glyphs(&self) -> impl Iterator + 'a + Clone { - ComponentGlyphIdIter { + pub fn component_glyphs_and_flags( + &self, + ) -> impl Iterator + 'a + Clone { + ComponentGlyphIdFlagsIter { cur_flags: CompositeGlyphFlags::empty(), done: false, cursor: FontData::new(self.component_data()).cursor(), @@ -490,7 +503,7 @@ impl<'a> CompositeGlyph<'a> { /// Returns the component count and TrueType interpreter instructions /// in a single pass. pub fn count_and_instructions(&self) -> (usize, Option<&'a [u8]>) { - let mut iter = ComponentGlyphIdIter { + let mut iter = ComponentGlyphIdFlagsIter { cur_flags: CompositeGlyphFlags::empty(), done: false, cursor: FontData::new(self.component_data()).cursor(), @@ -586,14 +599,14 @@ impl Iterator for ComponentIter<'_> { /// Significantly faster in cases where we're just processing the glyph /// tree, counting components or accessing instructions. #[derive(Clone)] -struct ComponentGlyphIdIter<'a> { +struct ComponentGlyphIdFlagsIter<'a> { cur_flags: CompositeGlyphFlags, done: bool, cursor: Cursor<'a>, } -impl Iterator for ComponentGlyphIdIter<'_> { - type Item = GlyphId; +impl Iterator for ComponentGlyphIdFlagsIter<'_> { + type Item = (GlyphId, CompositeGlyphFlags); fn next(&mut self) -> Option { if self.done { @@ -616,7 +629,7 @@ impl Iterator for ComponentGlyphIdIter<'_> { self.cursor.advance_by(8); } self.done = !flags.contains(CompositeGlyphFlags::MORE_COMPONENTS); - Some(glyph) + Some((glyph, flags)) } } @@ -945,6 +958,52 @@ mod tests { ); } + #[test] + fn simple_glyph_overlapping_contour_flag() { + let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap(); + let loca = font.loca(None).unwrap(); + let glyf = font.glyf().unwrap(); + let glyph_count = font.maxp().unwrap().num_glyphs(); + for gid in 0..glyph_count { + let glyph = match loca.get_glyf(GlyphId::new(gid), &glyf) { + Ok(Some(Glyph::Simple(glyph))) => glyph, + _ => continue, + }; + if gid == 3 { + // Only GID 3 has the overlap bit set + assert!(glyph.has_overlapping_contours()) + } else { + assert!(!glyph.has_overlapping_contours()) + } + } + } + + #[test] + fn composite_overlapping_contour_flag() { + let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap(); + let loca = font.loca(None).unwrap(); + let glyf = font.glyf().unwrap(); + let glyph_count = font.maxp().unwrap().num_glyphs(); + for gid in 0..glyph_count { + let glyph = match loca.get_glyf(GlyphId::new(gid), &glyf) { + Ok(Some(Glyph::Composite(glyph))) => glyph, + _ => continue, + }; + // Only GID 2, component 1 has the overlap bit set + for (component_ix, component) in glyph.components().enumerate() { + if gid == 2 && component_ix == 1 { + assert!(component + .flags + .contains(CompositeGlyphFlags::OVERLAP_COMPOUND)) + } else { + assert!(!component + .flags + .contains(CompositeGlyphFlags::OVERLAP_COMPOUND)) + } + } + } + } + #[test] fn compute_anchor_flags() { let anchor = Anchor::Offset { x: -128, y: 127 }; diff --git a/skrifa/src/scale/glyf/glyph.rs b/skrifa/src/scale/glyf/glyph.rs index d7407a5b1..5703786e9 100644 --- a/skrifa/src/scale/glyf/glyph.rs +++ b/skrifa/src/scale/glyf/glyph.rs @@ -41,6 +41,8 @@ pub struct ScalerGlyph<'a> { pub has_hinting: bool, /// True if the glyph requires variation delta processing. pub has_variations: bool, + /// True if the glyph contains any simple or compound overlap flags. + pub has_overlaps: bool, } impl<'a> ScalerGlyph<'a> { diff --git a/skrifa/src/scale/glyf/mem.rs b/skrifa/src/scale/glyf/mem.rs index 6bd38ba02..2e77ae7d9 100644 --- a/skrifa/src/scale/glyf/mem.rs +++ b/skrifa/src/scale/glyf/mem.rs @@ -155,6 +155,7 @@ mod tests { max_component_delta_stack: 4, has_hinting: false, has_variations: true, + has_overlaps: false, }; let required_size = outline_info.required_buffer_size(); let mut buf = vec![0u8; required_size]; @@ -185,6 +186,7 @@ mod tests { max_component_delta_stack: 4, has_hinting: false, has_variations: true, + has_overlaps: false, }; // Required size adds 4 bytes slop to account for internal alignment // requirements. So subtract 5 to force a failure. diff --git a/skrifa/src/scale/glyf/scaler.rs b/skrifa/src/scale/glyf/scaler.rs index 481758844..dda0e8805 100644 --- a/skrifa/src/scale/glyf/scaler.rs +++ b/skrifa/src/scale/glyf/scaler.rs @@ -112,12 +112,14 @@ impl<'a> Scaler<'a> { info.contours += simple.end_pts_of_contours().len(); info.has_hinting = info.has_hinting || simple.instruction_length() != 0; info.max_other_points = info.max_other_points.max(num_points_with_phantom); + info.has_overlaps |= simple.has_overlapping_contours(); } Glyph::Composite(composite) => { let (mut count, instructions) = composite.count_and_instructions(); count += PHANTOM_POINT_COUNT; let point_base = info.points; - for component in composite.component_glyphs() { + for (component, flags) in composite.component_glyphs_and_flags() { + info.has_overlaps |= flags.contains(CompositeGlyphFlags::OVERLAP_COMPOUND); let component_glyph = self.loca.get_glyf(component, &self.glyf)?; let Some(component_glyph) = component_glyph else { continue; @@ -733,3 +735,22 @@ impl<'a, H> ScalerInstance<'a, H> { self.phantom[3].y = self.phantom[2].y - F26Dot6::from_bits(vadvance); } } + +#[cfg(test)] +mod tests { + use super::*; + use read_fonts::{FontRef, TableProvider}; + + #[test] + fn overlap_flags() { + let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap(); + let scaler = Scaler::new(&font).unwrap(); + let glyph_count = font.maxp().unwrap().num_glyphs(); + for gid in 0..glyph_count { + let glyph = scaler.glyph(GlyphId::new(gid), false).unwrap(); + // GID 2 is a composite glyph with the overlap bit on a component + // GID 3 is a simple glyph with the overflag bit on the first flag + assert_eq!(glyph.has_overlaps, gid == 2 || gid == 3); + } + } +} From 55df1e674414f3339d3598699d187f2aadee516b Mon Sep 17 00:00:00 2001 From: Chad Brokaw Date: Wed, 23 Aug 2023 16:28:38 -0400 Subject: [PATCH 2/5] update comment and fix typo --- read-fonts/src/tables/glyf.rs | 6 +++--- skrifa/src/scale/glyf/scaler.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/read-fonts/src/tables/glyf.rs b/read-fonts/src/tables/glyf.rs index 23d38a4d0..bb171d065 100644 --- a/read-fonts/src/tables/glyf.rs +++ b/read-fonts/src/tables/glyf.rs @@ -488,8 +488,8 @@ impl<'a> CompositeGlyph<'a> { } } - /// Returns an iterator that yields the glyph identifier of each component - /// in the composite glyph. + /// Returns an iterator that yields the glyph identifier and flags of each + /// component in the composite glyph. pub fn component_glyphs_and_flags( &self, ) -> impl Iterator + 'a + Clone { @@ -594,7 +594,7 @@ impl Iterator for ComponentIter<'_> { } } -/// Iterator that only returns glyph identifiers for each component. +/// Iterator that only returns glyph identifiers and flags for each component. /// /// Significantly faster in cases where we're just processing the glyph /// tree, counting components or accessing instructions. diff --git a/skrifa/src/scale/glyf/scaler.rs b/skrifa/src/scale/glyf/scaler.rs index dda0e8805..190aad06a 100644 --- a/skrifa/src/scale/glyf/scaler.rs +++ b/skrifa/src/scale/glyf/scaler.rs @@ -749,7 +749,7 @@ mod tests { for gid in 0..glyph_count { let glyph = scaler.glyph(GlyphId::new(gid), false).unwrap(); // GID 2 is a composite glyph with the overlap bit on a component - // GID 3 is a simple glyph with the overflag bit on the first flag + // GID 3 is a simple glyph with the overlap bit on the first flag assert_eq!(glyph.has_overlaps, gid == 2 || gid == 3); } } From 48c5e3396e7914b13032114ef528cc9efee47924 Mon Sep 17 00:00:00 2001 From: Chad Brokaw Date: Wed, 23 Aug 2023 16:49:42 -0400 Subject: [PATCH 3/5] [skrifa] return overlap status from scaler Changes `Scaler::outline` to return a new `ScalerMetrics` struct that contains the overlap flag. This also has optional fields to represent metrics that may be adjusted by hinting. Based on #582 which must be merged first. Fixes #581 --- skrifa/src/scale/mod.rs | 22 ++++++++++++++++++++-- skrifa/src/scale/scaler.rs | 29 +++++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/skrifa/src/scale/mod.rs b/skrifa/src/scale/mod.rs index 9fc27e73a..ded5992ac 100644 --- a/skrifa/src/scale/mod.rs +++ b/skrifa/src/scale/mod.rs @@ -155,7 +155,7 @@ mod scaler; pub use read_fonts::types::Pen; pub use error::{Error, Result}; -pub use scaler::{Scaler, ScalerBuilder}; +pub use scaler::{Scaler, ScalerBuilder, ScalerMetrics}; use super::{ font::UniqueId, @@ -217,7 +217,7 @@ impl Context { #[cfg(test)] mod tests { use super::{Context, Size}; - use read_fonts::{scaler_test, FontRef}; + use read_fonts::{scaler_test, types::GlyphId, FontRef, TableProvider}; #[test] fn vazirmatin_var() { @@ -246,6 +246,24 @@ mod tests { ); } + #[test] + fn overlap_flags() { + let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap(); + let mut cx = Context::new(); + let mut path = scaler_test::Path { + elements: vec![], + is_cff: false, + }; + let mut scaler = cx.new_scaler().build(&font); + let glyph_count = font.maxp().unwrap().num_glyphs(); + for gid in 0..glyph_count { + let metrics = scaler.outline(GlyphId::new(gid), &mut path).unwrap(); + // GID 2 is a composite glyph with the overlap bit on a component + // GID 3 is a simple glyph with the overlap bit on the first flag + assert_eq!(metrics.has_overlaps, gid == 2 || gid == 3); + } + } + fn compare_glyphs(font_data: &[u8], expected_outlines: &str, is_cff: bool) { let font = FontRef::new(font_data).unwrap(); let outlines = scaler_test::parse_glyph_outlines(expected_outlines); diff --git a/skrifa/src/scale/scaler.rs b/skrifa/src/scale/scaler.rs index 1729ace30..e0f6bef5d 100644 --- a/skrifa/src/scale/scaler.rs +++ b/skrifa/src/scale/scaler.rs @@ -11,6 +11,20 @@ use read_fonts::{ TableProvider, }; +/// Information and adjusted metrics generated while scaling a glyph. +#[derive(Copy, Clone, Default, Debug)] +pub struct ScalerMetrics { + /// True if the underlying glyph contains flags indicating the + /// presence of overlapping contours or components. + pub has_overlaps: bool, + /// If present, an adjusted left side bearing value generated by the + /// scaler. + pub adjusted_lsb: Option, + /// If present, an adjusted advance width value generated by the + /// scaler. + pub adjusted_advance_width: Option, +} + /// Builder for configuring a glyph scaler. /// /// See the [module level documentation](crate::scale#building-a-scaler) @@ -206,7 +220,7 @@ impl<'a> Scaler<'a> { /// Loads a simple outline for the specified glyph identifier and invokes the functions /// in the given pen for the sequence of path commands that define the outline. - pub fn outline(&mut self, glyph_id: GlyphId, pen: &mut impl Pen) -> Result<()> { + pub fn outline(&mut self, glyph_id: GlyphId, pen: &mut impl Pen) -> Result { if let Some(outlines) = &mut self.outlines { outlines.outline(glyph_id, self.size, self.coords, pen) } else { @@ -230,7 +244,7 @@ impl<'a> Outlines<'a> { size: f32, coords: &'a [NormalizedCoord], pen: &mut impl Pen, - ) -> Result<()> { + ) -> Result { match self { Self::TrueType(scaler, buf) => { let glyph = scaler.glyph(glyph_id, false)?; @@ -242,14 +256,21 @@ impl<'a> Outlines<'a> { .memory_from_buffer(&mut buf[..]) .ok_or(Error::InsufficientMemory)?; let outline = scaler.outline(memory, &glyph, size, coords)?; - Ok(outline.to_path(pen)?) + outline.to_path(pen)?; + Ok(ScalerMetrics { + has_overlaps: glyph.has_overlaps, + ..Default::default() + }) } Self::PostScript(scaler, subfont) => { let subfont_index = scaler.subfont_index(glyph_id); if subfont_index != subfont.index() { *subfont = scaler.subfont(subfont_index, size, coords)?; } - Ok(scaler.outline(subfont, glyph_id, coords, false, pen)?) + scaler.outline(subfont, glyph_id, coords, false, pen)?; + // CFF does not have overlap flags and hinting never adjusts + // horizontal metrics + Ok(ScalerMetrics::default()) } } } From 649fba0207eb3a37444cafe71dd2c3b1d98bff68 Mon Sep 17 00:00:00 2001 From: Chad Brokaw Date: Thu, 24 Aug 2023 02:03:08 -0400 Subject: [PATCH 4/5] Address review feedback --- read-fonts/src/tables/glyf.rs | 80 +++++++++++++++++---------------- skrifa/src/scale/glyf/scaler.rs | 19 +++++--- skrifa/src/scale/mod.rs | 19 +++++--- 3 files changed, 68 insertions(+), 50 deletions(-) diff --git a/read-fonts/src/tables/glyf.rs b/read-fonts/src/tables/glyf.rs index bb171d065..7119c6803 100644 --- a/read-fonts/src/tables/glyf.rs +++ b/read-fonts/src/tables/glyf.rs @@ -958,50 +958,54 @@ mod tests { ); } - #[test] - fn simple_glyph_overlapping_contour_flag() { - let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap(); + // Test helper to enumerate all TrueType glyphs in the given font + fn all_glyphs(font_data: &[u8]) -> impl Iterator> { + let font = FontRef::new(font_data).unwrap(); let loca = font.loca(None).unwrap(); let glyf = font.glyf().unwrap(); let glyph_count = font.maxp().unwrap().num_glyphs(); - for gid in 0..glyph_count { - let glyph = match loca.get_glyf(GlyphId::new(gid), &glyf) { - Ok(Some(Glyph::Simple(glyph))) => glyph, - _ => continue, - }; - if gid == 3 { - // Only GID 3 has the overlap bit set - assert!(glyph.has_overlapping_contours()) - } else { - assert!(!glyph.has_overlapping_contours()) - } - } + (0..glyph_count).map(move |gid| loca.get_glyf(GlyphId::new(gid), &glyf).unwrap()) } #[test] - fn composite_overlapping_contour_flag() { - let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap(); - let loca = font.loca(None).unwrap(); - let glyf = font.glyf().unwrap(); - let glyph_count = font.maxp().unwrap().num_glyphs(); - for gid in 0..glyph_count { - let glyph = match loca.get_glyf(GlyphId::new(gid), &glyf) { - Ok(Some(Glyph::Composite(glyph))) => glyph, - _ => continue, - }; - // Only GID 2, component 1 has the overlap bit set - for (component_ix, component) in glyph.components().enumerate() { - if gid == 2 && component_ix == 1 { - assert!(component - .flags - .contains(CompositeGlyphFlags::OVERLAP_COMPOUND)) - } else { - assert!(!component - .flags - .contains(CompositeGlyphFlags::OVERLAP_COMPOUND)) - } - } - } + fn simple_glyph_overlapping_contour_flag() { + let gids_with_overlap: Vec<_> = all_glyphs(font_test_data::VAZIRMATN_VAR) + .enumerate() + .filter_map(|(gid, glyph)| match glyph { + Some(Glyph::Simple(glyph)) if glyph.has_overlapping_contours() => Some(gid), + _ => None, + }) + .collect(); + // Only GID 3 has the overlap bit set + let expected_gids_with_overlap = vec![3]; + assert_eq!(expected_gids_with_overlap, gids_with_overlap); + } + + #[test] + fn composite_glyph_overlapping_contour_flag() { + let gids_components_with_overlap: Vec<_> = all_glyphs(font_test_data::VAZIRMATN_VAR) + .enumerate() + .filter_map(|(gid, glyph)| match glyph { + Some(Glyph::Composite(glyph)) => Some((gid, glyph)), + _ => None, + }) + .flat_map(|(gid, glyph)| { + glyph + .components() + .enumerate() + .filter_map(move |(comp_ix, comp)| { + comp.flags + .contains(CompositeGlyphFlags::OVERLAP_COMPOUND) + .then_some((gid, comp_ix)) + }) + }) + .collect(); + // Only GID 2, component 1 has the overlap bit set + let expected_gids_components_with_overlap = vec![(2, 1)]; + assert_eq!( + expected_gids_components_with_overlap, + gids_components_with_overlap + ); } #[test] diff --git a/skrifa/src/scale/glyf/scaler.rs b/skrifa/src/scale/glyf/scaler.rs index 190aad06a..b919caa56 100644 --- a/skrifa/src/scale/glyf/scaler.rs +++ b/skrifa/src/scale/glyf/scaler.rs @@ -746,11 +746,18 @@ mod tests { let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap(); let scaler = Scaler::new(&font).unwrap(); let glyph_count = font.maxp().unwrap().num_glyphs(); - for gid in 0..glyph_count { - let glyph = scaler.glyph(GlyphId::new(gid), false).unwrap(); - // GID 2 is a composite glyph with the overlap bit on a component - // GID 3 is a simple glyph with the overlap bit on the first flag - assert_eq!(glyph.has_overlaps, gid == 2 || gid == 3); - } + // GID 2 is a composite glyph with the overlap bit on a component + // GID 3 is a simple glyph with the overlap bit on the first flag + let expected_gids_with_overlap = vec![2, 3]; + assert_eq!( + expected_gids_with_overlap, + (0..glyph_count) + .filter_map(|gid| scaler + .glyph(GlyphId::new(gid), false) + .unwrap() + .has_overlaps + .then_some(gid)) + .collect::>() + ); } } diff --git a/skrifa/src/scale/mod.rs b/skrifa/src/scale/mod.rs index ded5992ac..876c8570d 100644 --- a/skrifa/src/scale/mod.rs +++ b/skrifa/src/scale/mod.rs @@ -256,12 +256,19 @@ mod tests { }; let mut scaler = cx.new_scaler().build(&font); let glyph_count = font.maxp().unwrap().num_glyphs(); - for gid in 0..glyph_count { - let metrics = scaler.outline(GlyphId::new(gid), &mut path).unwrap(); - // GID 2 is a composite glyph with the overlap bit on a component - // GID 3 is a simple glyph with the overlap bit on the first flag - assert_eq!(metrics.has_overlaps, gid == 2 || gid == 3); - } + // GID 2 is a composite glyph with the overlap bit on a component + // GID 3 is a simple glyph with the overlap bit on the first flag + let expected_gids_with_overlap = vec![2, 3]; + assert_eq!( + expected_gids_with_overlap, + (0..glyph_count) + .filter_map(|gid| scaler + .outline(GlyphId::new(gid), &mut path) + .unwrap() + .has_overlaps + .then_some(gid)) + .collect::>() + ); } fn compare_glyphs(font_data: &[u8], expected_outlines: &str, is_cff: bool) { From 2ce614f12c05ffeaf3af8d35262e3683f22ec174 Mon Sep 17 00:00:00 2001 From: Chad Brokaw Date: Thu, 24 Aug 2023 02:14:31 -0400 Subject: [PATCH 5/5] fix conflicts --- read-fonts/src/tables/glyf.rs | 46 ----------------------------------- 1 file changed, 46 deletions(-) diff --git a/read-fonts/src/tables/glyf.rs b/read-fonts/src/tables/glyf.rs index d7b10789e..7119c6803 100644 --- a/read-fonts/src/tables/glyf.rs +++ b/read-fonts/src/tables/glyf.rs @@ -1008,52 +1008,6 @@ mod tests { ); } - #[test] - fn simple_glyph_overlapping_contour_flag() { - let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap(); - let loca = font.loca(None).unwrap(); - let glyf = font.glyf().unwrap(); - let glyph_count = font.maxp().unwrap().num_glyphs(); - for gid in 0..glyph_count { - let glyph = match loca.get_glyf(GlyphId::new(gid), &glyf) { - Ok(Some(Glyph::Simple(glyph))) => glyph, - _ => continue, - }; - if gid == 3 { - // Only GID 3 has the overlap bit set - assert!(glyph.has_overlapping_contours()) - } else { - assert!(!glyph.has_overlapping_contours()) - } - } - } - - #[test] - fn composite_overlapping_contour_flag() { - let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap(); - let loca = font.loca(None).unwrap(); - let glyf = font.glyf().unwrap(); - let glyph_count = font.maxp().unwrap().num_glyphs(); - for gid in 0..glyph_count { - let glyph = match loca.get_glyf(GlyphId::new(gid), &glyf) { - Ok(Some(Glyph::Composite(glyph))) => glyph, - _ => continue, - }; - // Only GID 2, component 1 has the overlap bit set - for (component_ix, component) in glyph.components().enumerate() { - if gid == 2 && component_ix == 1 { - assert!(component - .flags - .contains(CompositeGlyphFlags::OVERLAP_COMPOUND)) - } else { - assert!(!component - .flags - .contains(CompositeGlyphFlags::OVERLAP_COMPOUND)) - } - } - } - } - #[test] fn compute_anchor_flags() { let anchor = Anchor::Offset { x: -128, y: 127 };