Skip to content

Commit

Permalink
update CFF impl
Browse files Browse the repository at this point in the history
  • Loading branch information
dfrg committed Jan 30, 2024
1 parent 275ce85 commit 3190c4c
Show file tree
Hide file tree
Showing 10 changed files with 2,347 additions and 307 deletions.
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.1.8"
authors = ["Chad Brokaw <[email protected]>"]
edition = "2018"
description = "Font introspection, complex text shaping and glyph rendering."
license = "MIT OR Apache-2.0"
license = "MIT/Apache-2.0"
keywords = ["font", "shape", "glyph", "text"]
categories = ["graphics", "text-processing"]
repository = "https://github.com/dfrg/swash"
Expand All @@ -20,8 +20,8 @@ render = ["scale", "zeno/eval"]
[dependencies]
yazi = { version = "0.1.6", optional = true }
zeno = { version = "0.2.2", optional = true, default_features = false }
read-fonts = "0.10.0"
read-fonts = "0.15.2"

[dev-dependencies]
font-test-data= { git = "https://github.com/googlefonts/fontations", rev = "91ebdfd91bec9ae4ec34f6a7d5f01736b1b2eb6e" }
read-fonts = { version = "0.10.0", features = ["scaler_test"] }
font-test-data= { git = "https://github.com/googlefonts/fontations", rev = "10c27ef7bba1549fa37a3f41cd4870b2a24b1073" }
read-fonts = { version = "0.15.2", features = ["scaler_test"] }
2 changes: 1 addition & 1 deletion src/scale/cff/hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ impl HintMap {
if !first.is_locked() {
if let Some(ref initial) = initial {
if is_pair {
let mid = initial.map(scale, (second.coord + first.coord) / 2);
let mid = initial.map(scale, first.coord + (second.coord + first.coord) / 2);
let half = (second.coord - first.coord) / 2 * scale;
first.ds_coord = mid - half;
second.ds_coord = mid + half;
Expand Down
111 changes: 0 additions & 111 deletions src/scale/cff2/hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,6 @@ impl HintState {
state
}

#[cfg(test)]
fn zones(&self) -> &[BlueZone] {
&self.zones[..self.zone_count]
}

/// Initialize zones from the set of blues values.
///
/// See <https://gitlab.freedesktop.org/freetype/freetype/-/blob/80a507a6b8e3d2906ad2c8ba69329bd2fb2a85ef/src/psaux/psblues.c#L66>
Expand Down Expand Up @@ -982,109 +977,3 @@ fn half(value: Fixed) -> Fixed {
fn twice(value: Fixed) -> Fixed {
Fixed::from_bits(value.to_bits().wrapping_mul(2))
}

#[cfg(test)]
mod tests {
use super::{BlueZone, Blues, Fixed, HintParams, HintState};

// #[test]
// fn noto_serif_display_blue_zones() {
// fn make_blues(values: &[f64]) -> Blues {
// Blues::new(values.iter().copied().map(Fixed::from_f64))
// }
// // <BlueValues value="-15 0 536 547 571 582 714 726 760 772"/>
// // <OtherBlues value="-255 -240"/>
// // <BlueScale value="0.05"/>
// // <BlueShift value="7"/>
// // <BlueFuzz value="0"/>
// let params = HintParams {
// blues: make_blues(&[
// -15.0, 0.0, 536.0, 547.0, 571.0, 582.0, 714.0, 726.0, 760.0, 772.0,
// ]),
// other_blues: make_blues(&[-255.0, -240.0]),
// blue_scale: Fixed::from_f64(0.05),
// blue_shift: Fixed::from_i32(7),
// blue_fuzz: Fixed::ZERO,
// ..Default::default()
// };
// let state = HintState::new(&params, Fixed::ONE / Fixed::from_i32(64));
// assert!(!state.do_em_box_hints);
// assert_eq!(state.zone_count, 6);
// assert_eq!(state.boost, Fixed::from_bits(27035));
// assert!(state.supress_overshoot);
// // FreeType generates the following zones:
// let expected_zones = &[
// // csBottomEdge -983040 int
// // csTopEdge 0 int
// // csFlatEdge 0 int
// // dsFlatEdge 0 int
// // bottomZone 1 '\x1' unsigned char
// BlueZone {
// cs_bottom_edge: Fixed::from_bits(-983040),
// is_bottom: true,
// ..Default::default()
// },
// // csBottomEdge 35127296 int
// // csTopEdge 35848192 int
// // csFlatEdge 35127296 int
// // dsFlatEdge 589824 int
// // bottomZone 0 '\0' unsigned char
// BlueZone {
// cs_bottom_edge: Fixed::from_bits(35127296),
// cs_top_edge: Fixed::from_bits(35848192),
// cs_flat_edge: Fixed::from_bits(35127296),
// ds_flat_edge: Fixed::from_bits(589824),
// is_bottom: false,
// },
// // csBottomEdge 37421056 int
// // csTopEdge 38141952 int
// // csFlatEdge 37421056 int
// // dsFlatEdge 589824 int
// // bottomZone 0 '\0' unsigned char
// BlueZone {
// cs_bottom_edge: Fixed::from_bits(37421056),
// cs_top_edge: Fixed::from_bits(38141952),
// cs_flat_edge: Fixed::from_bits(37421056),
// ds_flat_edge: Fixed::from_bits(589824),
// is_bottom: false,
// },
// // csBottomEdge 46792704 int
// // csTopEdge 47579136 int
// // csFlatEdge 46792704 int
// // dsFlatEdge 786432 int
// // bottomZone 0 '\0' unsigned char
// BlueZone {
// cs_bottom_edge: Fixed::from_bits(46792704),
// cs_top_edge: Fixed::from_bits(47579136),
// cs_flat_edge: Fixed::from_bits(46792704),
// ds_flat_edge: Fixed::from_bits(786432),
// is_bottom: false,
// },
// // csBottomEdge 49807360 int
// // csTopEdge 50593792 int
// // csFlatEdge 49807360 int
// // dsFlatEdge 786432 int
// // bottomZone 0 '\0' unsigned char
// BlueZone {
// cs_bottom_edge: Fixed::from_bits(49807360),
// cs_top_edge: Fixed::from_bits(50593792),
// cs_flat_edge: Fixed::from_bits(49807360),
// ds_flat_edge: Fixed::from_bits(786432),
// is_bottom: false,
// },
// // csBottomEdge -16711680 int
// // csTopEdge -15728640 int
// // csFlatEdge -15728640 int
// // dsFlatEdge -262144 int
// // bottomZone 1 '\x1' unsigned char
// BlueZone {
// cs_bottom_edge: Fixed::from_bits(-16711680),
// cs_top_edge: Fixed::from_bits(-15728640),
// cs_flat_edge: Fixed::from_bits(-15728640),
// ds_flat_edge: Fixed::from_bits(-262144),
// is_bottom: true,
// },
// ];
// assert_eq!(state.zones(), expected_zones);
// }
}
149 changes: 0 additions & 149 deletions src/scale/cff2/scaler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,152 +586,3 @@ where
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use read_fonts::FontRef;

// fn check_blues(blues: &Blues, expected_values: &[(f64, f64)]) {
// for (i, blue) in blues.values().iter().enumerate() {
// let expected = expected_values[i];
// assert_eq!(blue.0, Fixed::from_f64(expected.0));
// assert_eq!(blue.1, Fixed::from_f64(expected.1));
// }
// }

#[test]
fn read_cff_static() {
let font = FontRef::new(font_test_data::NOTO_SERIF_DISPLAY_TRIMMED).unwrap();
let cff = Scaler::new(&font).unwrap();
assert!(!cff.is_cff2());
assert!(cff.top_dict.var_store.is_none());
assert!(cff.top_dict.font_dicts.is_none());
assert!(cff.top_dict.private_dict_range.is_some());
assert!(cff.top_dict.fd_select.is_none());
assert_eq!(cff.subfont_count(), 1);
assert_eq!(cff.subfont_index(GlyphId::new(1)), 0);
assert_eq!(cff.global_subrs().count(), 17);
// let subfont = cff.subfont(0, 0.0, Default::default(), false).unwrap();
// let hinting_params = subfont.hint_params;
// check_blues(
// &hinting_params.blues,
// &[
// (-15.0, 0.0),
// (536.0, 547.0),
// (571.0, 582.0),
// (714.0, 726.0),
// (760.0, 772.0),
// ],
// );
// check_blues(&hinting_params.other_blues, &[(-255.0, -240.0)]);
// assert_eq!(hinting_params.blue_scale, Fixed::from_f64(0.05));
// assert_eq!(hinting_params.blue_fuzz, Fixed::ZERO);
// assert_eq!(hinting_params.language_group, 0);
}

#[test]
fn read_cff2_static() {
let font = FontRef::new(font_test_data::CANTARELL_VF_TRIMMED).unwrap();
let cff = Scaler::new(&font).unwrap();
assert!(cff.is_cff2());
assert!(cff.top_dict.var_store.is_some());
assert!(cff.top_dict.font_dicts.is_some());
assert!(cff.top_dict.private_dict_range.is_none());
assert!(cff.top_dict.fd_select.is_none());
assert_eq!(cff.subfont_count(), 1);
assert_eq!(cff.subfont_index(GlyphId::new(1)), 0);
assert_eq!(cff.global_subrs().count(), 0);
// let subfont = cff.subfont(0, 0.0, Default::default(), false).unwrap();
// let hinting_params = subfont.hint_params;
// check_blues(
// &hinting_params.blues,
// &[(-10.0, 0.0), (482.0, 492.0), (694.0, 704.0), (739.0, 749.0)],
// );
// check_blues(&hinting_params.other_blues, &[(-227.0, -217.0)]);
// assert_eq!(hinting_params.blue_scale, Fixed::from_f64(0.0625));
// assert_eq!(hinting_params.blue_fuzz, Fixed::ONE);
// assert_eq!(hinting_params.language_group, 0);
}

#[test]
fn read_example_cff2_table() {
let cff = Scaler::from_cff2(
Cff2::read(FontData::new(font_test_data::cff2::EXAMPLE)).unwrap(),
1000,
)
.unwrap();
assert!(cff.is_cff2());
assert!(cff.top_dict.var_store.is_some());
assert!(cff.top_dict.font_dicts.is_some());
assert!(cff.top_dict.private_dict_range.is_none());
assert!(cff.top_dict.fd_select.is_none());
assert_eq!(cff.subfont_count(), 1);
assert_eq!(cff.subfont_index(GlyphId::new(1)), 0);
assert_eq!(cff.global_subrs().count(), 0);
}

#[test]
fn cff2_variable_outlines_match_freetype() {
compare_glyphs(
font_test_data::CANTARELL_VF_TRIMMED,
font_test_data::CANTARELL_VF_TRIMMED_GLYPHS,
);
}

#[test]
fn cff_static_outlines_match_freetype() {
compare_glyphs(
font_test_data::NOTO_SERIF_DISPLAY_TRIMMED,
font_test_data::NOTO_SERIF_DISPLAY_TRIMMED_GLYPHS,
);
}

/// For the given font data and extracted outlines, parse the extracted
/// outline data into a set of expected values and compare these with the
/// results generated by the scaler.
///
/// This will compare all outlines at various sizes and (for variable
/// fonts), locations in variation space.
fn compare_glyphs(font_data: &[u8], expected_outlines: &str) {
let font = FontRef::new(font_data).unwrap();
let outlines = read_fonts::scaler_test::parse_glyph_outlines(expected_outlines);
let scaler = super::Scaler::new(&font).unwrap();
let mut path = read_fonts::scaler_test::Path {
elements: vec![],
is_cff: true,
};
for expected_outline in &outlines {
if expected_outline.size == 0.0 && !expected_outline.coords.is_empty() {
continue;
}
path.elements.clear();
let subfont = scaler
.subfont(
scaler.subfont_index(expected_outline.glyph_id),
expected_outline.size,
&expected_outline.coords,
)
.unwrap();
scaler
.outline(
&subfont,
expected_outline.glyph_id,
&expected_outline.coords,
false,
&mut path,
)
.unwrap();
if path.elements != expected_outline.path {
panic!(
"mismatch in glyph path for id {} (size: {}, coords: {:?}): path: {:?} expected_path: {:?}",
expected_outline.glyph_id,
expected_outline.size,
expected_outline.coords,
&path.elements,
&expected_outline.path
);
}
}
}
}
Loading

0 comments on commit 3190c4c

Please sign in to comment.