Skip to content

Commit

Permalink
[skrifa] tthint: use cvar table
Browse files Browse the repository at this point in the history
Applies cvar deltas to the cvt.
  • Loading branch information
dfrg committed Mar 15, 2024
1 parent 5dba11d commit 9272757
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 32 deletions.
Binary file modified font-test-data/test_data/ttf/cvar.ttf
Binary file not shown.
49 changes: 25 additions & 24 deletions font-test-data/test_data/ttx/cvar.ttx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
<GlyphOrder>
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
<GlyphID id="0" name=".notdef"/>
<GlyphID id="1" name="uni0020"/>
<GlyphID id="2" name="uni0068"/>
<GlyphID id="3" name="uni006E"/>
<GlyphID id="4" name="uni006F"/>
</GlyphOrder>

<head>
Expand Down Expand Up @@ -125,28 +121,8 @@

<hmtx>
<mtx name=".notdef" width="500" lsb="50"/>
<mtx name="uni0020" width="260" lsb="0"/>
<mtx name="uni0068" width="635" lsb="18"/>
<mtx name="uni006E" width="645" lsb="28"/>
<mtx name="uni006F" width="577" lsb="55"/>
</hmtx>

<cmap>
<tableVersion version="0"/>
<cmap_format_4 platformID="0" platEncID="3" language="0">
<map code="0x20" name="uni0020"/><!-- SPACE -->
<map code="0x68" name="uni0068"/><!-- LATIN SMALL LETTER H -->
<map code="0x6e" name="uni006E"/><!-- LATIN SMALL LETTER N -->
<map code="0x6f" name="uni006F"/><!-- LATIN SMALL LETTER O -->
</cmap_format_4>
<cmap_format_4 platformID="3" platEncID="1" language="0">
<map code="0x20" name="uni0020"/><!-- SPACE -->
<map code="0x68" name="uni0068"/><!-- LATIN SMALL LETTER H -->
<map code="0x6e" name="uni006E"/><!-- LATIN SMALL LETTER N -->
<map code="0x6f" name="uni006F"/><!-- LATIN SMALL LETTER O -->
</cmap_format_4>
</cmap>

<cvt>
<cv index="0" value="760"/>
<cv index="1" value="10"/>
Expand Down Expand Up @@ -274,6 +250,24 @@
<!-- The 'loca' table will be calculated by the compiler -->
</loca>

<glyf>
<TTGlyph name=".notdef" xMin="51" yMin="-250" xMax="461" yMax="950">
<contour>
<pt x="51" y="-250" on="1"/>
<pt x="51" y="950" on="1"/>
<pt x="461" y="950" on="1"/>
<pt x="461" y="-250" on="1"/>
</contour>
<contour>
<pt x="102" y="-199" on="1"/>
<pt x="410" y="-199" on="1"/>
<pt x="410" y="899" on="1"/>
<pt x="102" y="899" on="1"/>
</contour>
<instructions/>
</TTGlyph>
</glyf>

<post>
<formatType value="2.0"/>
<italicAngle value="0.0"/>
Expand Down Expand Up @@ -414,6 +408,13 @@
</tuple>
</cvar>

<gvar>
<version value="1"/>
<reserved value="0"/>
<glyphVariations glyph=".notdef">
</glyphVariations>
</gvar>

<fvar>

<!-- Weight -->
Expand Down
71 changes: 63 additions & 8 deletions skrifa/src/outline/glyf/hint/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl HintInstance {
mode: HintingMode,
coords: &[F2Dot14],
) -> Result<(), HintError> {
self.setup(outlines, scale);
self.setup(outlines, scale, coords);
let twilight_contours = [self.twilight_scaled.len() as u16];
let twilight = Zone::new(
&[],
Expand Down Expand Up @@ -157,7 +157,7 @@ impl HintInstance {
}

/// Captures limits, resizes buffers and scales the CVT.
fn setup(&mut self, outlines: &Outlines, scale: i32) {
fn setup(&mut self, outlines: &Outlines, scale: i32, coords: &[F2Dot14]) {
let axis_count = outlines
.gvar
.as_ref()
Expand All @@ -171,13 +171,40 @@ impl HintInstance {
Definition::default(),
);
self.cvt.clear();
if let Some(cvar) = outlines.cvar.as_ref() {
// First accumulate all the deltas in 16.16
self.cvt.resize(outlines.cvt.len(), 0);
if let Ok(var_data) = cvar.variation_data(axis_count) {
for (tuple, scalar) in var_data.active_tuples_at(coords) {
for delta in tuple.deltas() {
let ix = delta.position as usize;
if let Some(value) = self.cvt.get_mut(ix) {
*value += delta.apply_scalar(scalar).to_bits();
}
}
}
}
// Now add the base CVT values
for (value, base_value) in self.cvt.iter_mut().zip(outlines.cvt.iter()) {
// Deltas are converted from 16.16 to 26.6
// See <https://gitlab.freedesktop.org/freetype/freetype/-/blob/57617782464411201ce7bbc93b086c1b4d7d84a5/src/truetype/ttgxvar.c#L3822>
let delta = Fixed::from_bits(*value).to_f26dot6().to_bits();
let base_value = base_value.get() as i32 * 64;
*value = base_value + delta;
}
} else {
// CVT values are converted to 26.6 on load
// See <https://gitlab.freedesktop.org/freetype/freetype/-/blob/57617782464411201ce7bbc93b086c1b4d7d84a5/src/truetype/ttpload.c#L350>
self.cvt
.extend(outlines.cvt.iter().map(|value| (value.get() as i32) * 64));
}
// More weird scaling. This is due to the fact that CVT values are
// already in 26.6
// See <https://gitlab.freedesktop.org/freetype/freetype/-/blob/57617782464411201ce7bbc93b086c1b4d7d84a5/src/truetype/ttobjs.c#L996>
let scale = Fixed::from_bits(scale >> 6);
self.cvt.extend(
outlines
.cvt
.iter()
.map(|value| (Fixed::from_bits(value.get() as i32 * 64) * scale).to_bits()),
);
for value in &mut self.cvt {
*value = (Fixed::from_bits(*value) * scale).to_bits();
}
self.storage.clear();
self.storage.resize(outlines.max_storage as usize, 0);
let max_twilight_points = outlines.max_twilight_points as usize;
Expand All @@ -195,3 +222,31 @@ impl HintInstance {
self.graphics = RetainedGraphicsState::default();
}
}

#[cfg(test)]
mod tests {
use super::{super::super::Outlines, HintInstance};
use read_fonts::{types::F2Dot14, FontRef};

#[test]
fn scaled_cvar_cvt() {
let font = FontRef::new(font_test_data::CVAR).unwrap();
let outlines = Outlines::new(&font).unwrap();
let mut instance = HintInstance::default();
let coords = [0.5, -0.5].map(F2Dot14::from_f32);
let ppem = 16;
// ppem * 64 / upem
let scale = 67109;
instance
.reconfigure(&outlines, scale, ppem, Default::default(), &coords)
.unwrap();
let expected = [
778, 10, 731, 0, 731, 10, 549, 10, 0, 0, 0, -10, 0, -10, -256, -10, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 137, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 60, 0, 81, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
assert_eq!(&instance.cvt, &expected);
}
}
3 changes: 3 additions & 0 deletions skrifa/src/outline/glyf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::GLYF_COMPOSITE_RECURSION_LIMIT;

use read_fonts::{
tables::{
cvar::Cvar,
glyf::{
Anchor, CompositeGlyph, CompositeGlyphFlags, Glyf, Glyph, PointMarker, SimpleGlyph,
},
Expand All @@ -43,6 +44,7 @@ pub struct Outlines<'a> {
fpgm: &'a [u8],
prep: &'a [u8],
cvt: &'a [BigEndian<i16>],
cvar: Option<Cvar<'a>>,
max_function_defs: u16,
max_instruction_defs: u16,
max_twilight_points: u16,
Expand Down Expand Up @@ -106,6 +108,7 @@ impl<'a> Outlines<'a> {
.data_for_tag(Tag::new(b"cvt "))
.and_then(|d| d.read_array(0..d.len()).ok())
.unwrap_or_default(),
cvar: font.cvar().ok(),
max_function_defs,
max_instruction_defs,
max_twilight_points,
Expand Down

0 comments on commit 9272757

Please sign in to comment.