Skip to content

Commit

Permalink
[fea-rs] Add options to skip GPOS or GSUB
Browse files Browse the repository at this point in the history
This is a fairly quick pass, and if future profiling suggests it is
useful we could be more fine-grained in deciding what code to skip
executing. In particular we still perform the full validation pass,
where we could skip some work there as well.
  • Loading branch information
cmyr committed Feb 6, 2024
1 parent d40a9c8 commit e54805c
Show file tree
Hide file tree
Showing 8 changed files with 4,063 additions and 12 deletions.
19 changes: 16 additions & 3 deletions fea-rs/src/bin/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ fn run() -> Result<(), Error> {
}

let var_info = args.get_var_info().transpose()?;
let opts = args.opts();

let mut compiler: Compiler<'_, NopFeatureProvider, MockVariationInfo> =
Compiler::new(fea, &glyph_names).with_opts(Opts::new().make_post_table(args.post));
Compiler::new(fea, &glyph_names).with_opts(opts);
if let Some(var_info) = var_info.as_ref() {
log::info!("compiling with {} mock variation axes", var_info.axes.len());
for axis in &var_info.axes {
Expand All @@ -53,9 +54,8 @@ fn run() -> Result<(), Error> {
let compiled = compiler.compile()?;

let path = args.out_path();
let opts = Opts::new().make_post_table(args.post);
let raw_font = compiled
.to_binary(&glyph_names, opts)
.to_binary(&glyph_names)
.expect("ttf compile failed");

log::info!("writing {} bytes to {}", raw_font.len(), path.display());
Expand Down Expand Up @@ -137,6 +137,12 @@ struct Args {
/// Optionally write a post table to the generated font
#[arg(short, long)]
post: bool,

#[arg(long)]
skip_gpos: bool,

#[arg(long)]
skip_gsub: bool,
}

impl Args {
Expand Down Expand Up @@ -184,6 +190,13 @@ impl Args {
self.glyph_order.as_deref()
}

fn opts(&self) -> Opts {
Opts::new()
.make_post_table(self.post)
.compile_gpos(!self.skip_gpos)
.compile_gsub(!self.skip_gsub)
}

fn out_path(&self) -> &Path {
self.out_path
.as_deref()
Expand Down
10 changes: 7 additions & 3 deletions fea-rs/src/compile/compile_ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ impl<'a, F: FeatureProvider, V: VariationInfo> CompilationCtx<'a, F, V> {
.unwrap_or_default();
let mut ivs = VariationStoreBuilder::new(axis_count);

let (mut gsub, mut gpos) = self.lookups.build(&self.features, &mut ivs);
let (mut gsub, mut gpos) = self.lookups.build(&self.features, &mut ivs, &self.opts);
if !ivs.is_empty() {
self.tables
.gdef
Expand Down Expand Up @@ -1777,9 +1777,13 @@ impl<'a, F: FeatureProvider, V: VariationInfo> CompilationCtx<'a, F, V> {
} else if let Some(lookup) = typed::LookupBlock::cast(item) {
self.resolve_lookup_block(lookup);
} else if let Some(rule) = typed::GsubStatement::cast(item) {
self.add_gsub_statement(rule);
if self.opts.compile_gsub {
self.add_gsub_statement(rule);
}
} else if let Some(rule) = typed::GposStatement::cast(item) {
self.add_gpos_statement(rule)
if self.opts.compile_gpos {
self.add_gpos_statement(rule)
}
} else if item.kind() == Kind::Semi {
// continue
} else {
Expand Down
11 changes: 6 additions & 5 deletions fea-rs/src/compile/lookups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use write_fonts::{
use crate::{
common::{GlyphId, GlyphOrClass, GlyphSet},
compile::{lookups::contextual::ChainOrNot, metrics::ValueRecord},
Kind,
Kind, Opts,
};

use super::{features::AllFeatures, metrics::Anchor, tables::ClassId, tags};
Expand Down Expand Up @@ -646,6 +646,7 @@ impl AllLookups {
&self,
features: &AllFeatures,
var_store: &mut VariationStoreBuilder,
opts: &Opts,
) -> (Option<write_gsub::Gsub>, Option<write_gpos::Gpos>) {
let mut gpos_builder = PosSubBuilder::new(self.gpos.clone());
let mut gsub_builder = PosSubBuilder::new(self.gsub.clone());
Expand All @@ -661,17 +662,17 @@ impl AllLookups {
let (gpos_idxes, gsub_idxes) = feature_lookups.split_base_lookups();
let mut gpos_feat_id = None;
let mut gsub_feat_id = None;
if !gpos_idxes.is_empty() {
if opts.compile_gpos && !gpos_idxes.is_empty() {
gpos_feat_id = Some(gpos_builder.add(*key, gpos_idxes.clone(), required));
}

if !gsub_idxes.is_empty() {
if opts.compile_gsub && !gsub_idxes.is_empty() {
gsub_feat_id = Some(gsub_builder.add(*key, gsub_idxes.clone(), required));
}

let variations = feature_lookups.split_variations();
for (cond, gpos_var_idxes, gsub_var_idxes) in variations {
if !gpos_var_idxes.is_empty() {
if opts.compile_gpos && !gpos_var_idxes.is_empty() {
// add the lookups for the base feature
let mut all_ids = gpos_idxes.clone();
all_ids.extend(gpos_var_idxes);
Expand All @@ -682,7 +683,7 @@ impl AllLookups {
.get_or_insert_with(|| gpos_builder.add(*key, Vec::new(), false));
gpos_builder.add_variation(*feat_id, cond, all_ids);
}
if !gsub_var_idxes.is_empty() {
if opts.compile_gsub && !gsub_var_idxes.is_empty() {
// add the lookups for the base feature
let mut all_ids = gsub_idxes.clone();
all_ids.extend(gsub_var_idxes);
Expand Down
43 changes: 43 additions & 0 deletions fea-rs/src/compile/opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,46 @@ impl Default for Opts {
}
}
}

#[cfg(test)]
mod tests {

static OSWALD_DIR: &str = "./test-data/real-files/oswald";
use std::path::Path;

use crate::{
compile::{Compilation, MockVariationInfo, NopFeatureProvider},
Compiler,
};

use super::*;

#[test]
fn skip_tables() {
fn compile_oswald(opts: Opts) -> Compilation {
let glyph_order = Path::new(OSWALD_DIR).join("glyph_order.txt");
let features = Path::new(OSWALD_DIR).join("features.fea");
let glyph_order = std::fs::read_to_string(glyph_order).unwrap();
let glyph_order = crate::compile::parse_glyph_order(&glyph_order).unwrap();
Compiler::<NopFeatureProvider, MockVariationInfo>::new(&features, &glyph_order)
.with_opts(opts)
.compile()
.unwrap()
}

// compile everything:
let compilation = compile_oswald(Opts::new());
assert!(compilation.gpos.is_some());
assert!(compilation.gsub.is_some());

// only gpos
let compilation = compile_oswald(Opts::new().compile_gsub(false));
assert!(compilation.gpos.is_some());
assert!(compilation.gsub.is_none());

// only gsub
let compilation = compile_oswald(Opts::new().compile_gpos(false));
assert!(compilation.gpos.is_none());
assert!(compilation.gsub.is_some());
}
}
1 change: 1 addition & 0 deletions fea-rs/test-data/real-files/oswald/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file includes GPOS features generated by fontmake feature writers.
Loading

0 comments on commit e54805c

Please sign in to comment.