Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
5f8ec23
Add the interjector type
LaurenzV Aug 9, 2025
52dea33
Progress towards adding a skrifa interjector
LaurenzV Aug 9, 2025
c4e7132
Use i16 instead of u16 for lsb
LaurenzV Aug 9, 2025
7d407d1
Make it build
LaurenzV Aug 9, 2025
631c216
Downgrade skrifa
LaurenzV Aug 9, 2025
72ac9a9
require string for location
LaurenzV Aug 9, 2025
fb353bf
Reformat + relax kurbo dep
LaurenzV Aug 9, 2025
5f59f2e
Bump skrifa
LaurenzV Aug 9, 2025
23964c9
Add cubic beziers to interjector
LaurenzV Aug 11, 2025
66b54d2
Distinguish between FontKind and FontFlavor
LaurenzV Aug 11, 2025
72799e8
Use a closure in glyf subset
LaurenzV Aug 11, 2025
3f8f091
Add a subset_with function
LaurenzV Aug 11, 2025
f73ffc9
More adjustments
LaurenzV Aug 11, 2025
c53e5ce
Synthesize maxp table for CFF2
LaurenzV Aug 11, 2025
accf866
Allow passing variation coordinates to tests
LaurenzV Aug 12, 2025
d13b079
Only suport variations in fonttools tests
LaurenzV Aug 12, 2025
885bf7d
Add variable noto sans
LaurenzV Aug 12, 2025
e467044
Allow variation coordinates for fonttools tests
LaurenzV Aug 12, 2025
57487f8
Add a comment
LaurenzV Aug 12, 2025
a7f792f
Add test cases
LaurenzV Aug 12, 2025
067e0a1
Add doc comment
LaurenzV Aug 12, 2025
4673066
Run tests with variable fonts feature in CI
LaurenzV Aug 12, 2025
39a1606
Add a test case with cantarell
LaurenzV Aug 12, 2025
6cf68e9
Make variable fonts a default feature
LaurenzV Aug 12, 2025
ff18e70
Get rid of dynamic dispatching
LaurenzV Aug 14, 2025
36643ba
kurbo to 0.11.2
LaurenzV Aug 14, 2025
2add572
Minor fixes
LaurenzV Aug 14, 2025
b0b9960
More small tweaks
LaurenzV Aug 14, 2025
848552d
Unused import
LaurenzV Aug 14, 2025
cd02c38
Fix `build` in CI
LaurenzV Aug 15, 2025
9b6c7a3
Rename variable_fonts feature
LaurenzV Aug 15, 2025
d06485f
Regenerate tests to include new name records
LaurenzV Aug 15, 2025
64b4a69
Fix comment
LaurenzV Aug 15, 2025
73987a0
Make `custom_maxp_data` a doc comment
LaurenzV Aug 15, 2025
001c5d1
Document interjector
LaurenzV Aug 15, 2025
7a2e217
Don't make interjector pub(crate)
LaurenzV Aug 15, 2025
5160358
Move `MaxpData`
LaurenzV Aug 15, 2025
1dbd913
Fix whitespaces
LaurenzV Aug 15, 2025
bf4861f
Adjust visibilities in maxpData
LaurenzV Aug 15, 2025
93b474f
Add feature flag
LaurenzV Aug 15, 2025
1df5d06
Add `subset_with_variations` method
LaurenzV Aug 15, 2025
433b940
Increase tolerance a bit
LaurenzV Aug 15, 2025
1d5db4a
Add a comment
LaurenzV Aug 15, 2025
3784a81
Move metric extraction into custom function
LaurenzV Aug 15, 2025
6f018c2
Fix build for no default features
LaurenzV Aug 15, 2025
8e82592
Expose the `Tag` struct and use it
LaurenzV Aug 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
- run: cargo build
name: Build
- run: cargo build --no-default-features
name: Build without default features
- run: cargo test
name: Run tests

Expand Down
102 changes: 98 additions & 4 deletions Cargo.lock

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

9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,16 @@ repository = { workspace = true }
readme = { workspace = true }
license = { workspace = true }

[features]
default = ["variable-fonts"]
variable-fonts = ["dep:skrifa", "dep:write-fonts", "dep:kurbo"]

[dependencies]
rustc-hash = "2.1"
skrifa = { optional = true, version = "0.33" }
kurbo = { optional = true, version = "0.11" }
write-fonts = { optional = true, version = "0.39.1"}

[dev-dependencies]
skrifa = "0.29.0"
skrifa = "0.33"
ttf-parser = "0.25.1"
2 changes: 2 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ SOFTWARE.
The SIL OPEN FONT LICENSE Version 1.1 applies to the following fonts:
- fonts/ClickerScript-Regular.ttf
- fonts/MPLUS1p-Regular.ttf
- fonts/Cantarell-VF.otf
- fonts/NotoSans-Regular.ttf
- fonts/NotoSans-Regular_var.ttf
- fonts/NotoSansCJKsc-Bold-subset1.otf
- fonts/NotoSansCJKsc-Regular.otf
- fonts/Syne-Regular_subset.oft (Copyright 2017 The Syne Project Authors (https://gitlab.com/bonjour-monde/fonderie/syne-typeface))
Expand Down
Binary file added fonts/Cantarell-VF.otf
Binary file not shown.
Binary file added fonts/NotoSans-Regular_var.ttf
Binary file not shown.
25 changes: 25 additions & 0 deletions src/cff2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use crate::interjector::Interjector;
use crate::Error::MalformedFont;
use crate::{glyf, Context, MaxpData};
use std::borrow::Cow;

/// CFF2 fonts will currently be converted into TTF fonts.
pub fn subset(ctx: &mut Context) -> crate::Result<()> {
let mut maxp_data = MaxpData::default();

let result = glyf::subset_with(ctx, |old_gid, ctx| {
let data = match &ctx.interjector {
// We reject CFF2 fonts earlier if `variable-fonts` feature is not enabled.
Interjector::Dummy(_) => unreachable!(),
#[cfg(feature = "variable-fonts")]
Interjector::Skrifa(s) => {
Cow::Owned(s.glyph_data(&mut maxp_data, old_gid).ok_or(MalformedFont)?)
}
};

Ok(data)
});

ctx.custom_maxp_data = Some(maxp_data);
result
}
41 changes: 32 additions & 9 deletions src/glyf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,29 @@ pub fn closure(face: &Face, glyph_remapper: &mut GlyphRemapper) -> Result<()> {
}

pub fn subset(ctx: &mut Context) -> Result<()> {
let subsetted_entries = subset_glyf_entries(ctx)?;
let table = Table::new(&ctx.face).ok_or(MalformedFont)?;
let mut _maxp = MaxpData::default();

subset_with(ctx, |old_gid, ctx| {
let data = match &ctx.interjector {
Interjector::Dummy(_) => {
Cow::Borrowed(table.glyph_data(old_gid).ok_or(MalformedFont)?)
}
#[cfg(feature = "variable-fonts")]
Interjector::Skrifa(s) => {
Cow::Owned(s.glyph_data(&mut _maxp, old_gid).ok_or(MalformedFont)?)
}
};

Ok(data)
})
}

pub(crate) fn subset_with<'a>(
ctx: &mut Context<'a>,
glyph_data_fn: impl FnMut(u16, &Context<'a>) -> Result<Cow<'a, [u8]>>,
) -> Result<()> {
let subsetted_entries = subset_glyf_entries(ctx, glyph_data_fn)?;

let mut sub_glyf = Writer::new();
let mut sub_loca = Writer::new();
Expand Down Expand Up @@ -112,29 +134,30 @@ impl<'a> Table<'a> {
}
}

fn subset_glyf_entries<'a>(ctx: &mut Context<'a>) -> Result<Vec<Cow<'a, [u8]>>> {
let table = Table::new(&ctx.face).ok_or(MalformedFont)?;

fn subset_glyf_entries<'a>(
ctx: &mut Context<'a>,
mut glyph_data_fn: impl FnMut(u16, &Context<'a>) -> Result<Cow<'a, [u8]>>,
) -> Result<Vec<Cow<'a, [u8]>>> {
let mut size = 0;
let mut glyf_entries = vec![];

for old_gid in ctx.mapper.remapped_gids() {
let glyph_data = table.glyph_data(old_gid).ok_or(MalformedFont)?;
let glyph_data = glyph_data_fn(old_gid, ctx)?;

// Empty glyph.
if glyph_data.is_empty() {
glyf_entries.push(Cow::Borrowed(glyph_data));
glyf_entries.push(glyph_data);
continue;
}

let mut r = Reader::new(glyph_data);
let mut r = Reader::new(&glyph_data);
let num_contours = r.read::<i16>().ok_or(MalformedFont)?;

let glyph_data = if num_contours < 0 {
Cow::Owned(remap_component_glyph(&ctx.mapper, glyph_data)?)
Cow::Owned(remap_component_glyph(&ctx.mapper, &glyph_data)?)
} else {
// Simple glyphs don't need any subsetting.
Cow::Borrowed(glyph_data)
glyph_data
};

let mut len = glyph_data.len();
Expand Down
Loading