Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
rsheeter committed May 26, 2023
1 parent 77ad685 commit f62b28e
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 75 deletions.
20 changes: 15 additions & 5 deletions fontbe/src/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ use fea_rs::{
};
use fontir::{ir::Features, orchestration::Flags};
use log::{debug, error, trace, warn};
use write_fonts::FontBuilder;
use read_fonts::{FontRef, TableProvider};
use write_fonts::{from_obj::ToOwnedTable, FontBuilder};

use fontdrasil::orchestration::Work;

use crate::{
error::Error,
orchestration::{BeWork, Context},
orchestration::{BeWork, Context, WorkId},
};

pub struct FeatureWork {}
Expand Down Expand Up @@ -114,7 +115,6 @@ impl Work<Context, Error> for FeatureWork {
if let Features::Empty = *features {
// set a default in place so subsequent compiles skip this step
trace!("No fea file, dull compile");
context.set_features(FontBuilder::default());
return Ok(());
}
let glyph_order = &context.ir.get_final_static_metadata().glyph_order;
Expand All @@ -132,8 +132,18 @@ impl Work<Context, Error> for FeatureWork {
write_debug_fea(context, result.is_err(), "compile failed", fea_content);
}
}
let font = result?;
context.set_features(font);
let buf = result?.build();
let font = FontRef::new(&buf).unwrap();
if let Some(gpos) = font.gpos().ok() {
context.set_gpos(gpos.to_owned_table());
}
if let Some(gsub) = font.gsub().ok() {
context.set_gsub(gsub.to_owned_table());
}
// Enables the assumption that if the file exists features were compiled
if context.flags.contains(Flags::EMIT_IR) {
fs::write(context.paths.target_file(&WorkId::Features), "1").map_err(Error::IoError)?;
}
Ok(())
}
}
35 changes: 33 additions & 2 deletions fontbe/src/font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ use fontdrasil::orchestration::Work;
use log::debug;
use read_fonts::{
tables::{
avar::Avar, cmap::Cmap, fvar::Fvar, glyf::Glyf, gvar::Gvar, head::Head, hhea::Hhea,
hmtx::Hmtx, loca::Loca, maxp::Maxp, name::Name, os2::Os2, post::Post,
avar::Avar, cmap::Cmap, fvar::Fvar, glyf::Glyf, gpos::Gpos, gsub::Gsub, gvar::Gvar,
head::Head, hhea::Hhea, hmtx::Hmtx, loca::Loca, maxp::Maxp, name::Name, os2::Os2,
post::Post,
},
types::Tag,
TopLevelTable,
Expand Down Expand Up @@ -36,6 +37,8 @@ const TABLES_TO_MERGE: &[(WorkId, Tag, TableType)] = &[
(WorkId::Hhea, Hhea::TAG, TableType::Static),
(WorkId::Hmtx, Hmtx::TAG, TableType::Static),
(WorkId::Glyf, Glyf::TAG, TableType::Static),
(WorkId::Gpos, Gpos::TAG, TableType::Static),
(WorkId::Gsub, Gsub::TAG, TableType::Static),
(WorkId::Gvar, Gvar::TAG, TableType::Variable),
(WorkId::Loca, Loca::TAG, TableType::Static),
(WorkId::Maxp, Maxp::TAG, TableType::Static),
Expand All @@ -44,6 +47,27 @@ const TABLES_TO_MERGE: &[(WorkId, Tag, TableType)] = &[
(WorkId::Post, Post::TAG, TableType::Static),
];

fn has(context: &Context, id: WorkId) -> bool {
match id {
WorkId::Avar => context.has_avar(),
WorkId::Cmap => context.has_cmap(),
WorkId::Fvar => context.has_fvar(),
WorkId::Head => context.has_head(),
WorkId::Hhea => context.has_hhea(),
WorkId::Hmtx => context.has_hmtx(),
WorkId::Glyf => context.has_glyf_loca(),
WorkId::Gpos => context.has_gpos(),
WorkId::Gsub => context.has_gsub(),
WorkId::Gvar => context.has_gvar(),
WorkId::Loca => context.has_glyf_loca(),
WorkId::Maxp => context.has_maxp(),
WorkId::Name => context.has_name(),
WorkId::Os2 => context.has_os2(),
WorkId::Post => context.has_post(),
_ => false,
}
}

fn bytes_for(context: &Context, id: WorkId) -> Result<Vec<u8>, Error> {
let bytes = match id {
WorkId::Avar => to_bytes(context.get_avar().as_ref()),
Expand All @@ -53,6 +77,8 @@ fn bytes_for(context: &Context, id: WorkId) -> Result<Vec<u8>, Error> {
WorkId::Hhea => to_bytes(&*context.get_hhea()),
WorkId::Hmtx => context.get_hmtx().get().to_vec(),
WorkId::Glyf => context.get_glyf_loca().glyf.clone(),
WorkId::Gpos => to_bytes(&*context.get_gpos()),
WorkId::Gsub => to_bytes(&*context.get_gsub()),
WorkId::Gvar => context.get_gvar().get().to_vec(),
WorkId::Loca => context.get_glyf_loca().raw_loca.clone(),
WorkId::Maxp => to_bytes(&*context.get_maxp()),
Expand Down Expand Up @@ -81,11 +107,16 @@ impl Work<Context, Error> for FontWork {
debug!("Skip {tag} because this is a static font");
continue;
}
if !has(context, work_id.clone()) {
debug!("Skip {tag} because we don't have it");
continue;
}
debug!("Grabbing {tag} for final font");
let bytes = bytes_for(context, work_id.clone())?;
builder.add_table(*tag, bytes);
}

debug!("Building font");
let font = builder.build();
debug!("Assembled {} byte font", font.len());
context.set_font(Bytes::new(font));
Expand Down
91 changes: 43 additions & 48 deletions fontbe/src/orchestration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ use write_fonts::{
cmap::Cmap,
fvar::Fvar,
glyf::{Bbox, SimpleGlyph},
gpos::Gpos,
gsub::Gsub,
gvar::GlyphDeltas,
head::Head,
hhea::Hhea,
Expand All @@ -35,7 +37,7 @@ use write_fonts::{
variations::Tuple,
},
validate::Validate,
FontBuilder, FontWrite, OtRound,
FontWrite, OtRound,
};
use write_fonts::{from_obj::FromTableRef, tables::glyf::CompositeGlyph};

Expand All @@ -61,6 +63,8 @@ pub enum WorkId {
Fvar,
Glyf,
GlyfFragment(GlyphName),
Gpos,
Gsub,
Gvar,
GvarFragment(GlyphName),
Head,
Expand Down Expand Up @@ -346,15 +350,15 @@ pub struct Context {

// work results we've completed or restored from disk
// We create individual caches so we can return typed results from get fns
features: Arc<RwLock<Option<Arc<Vec<u8>>>>>,

glyphs: Arc<RwLock<HashMap<GlyphName, Arc<Glyph>>>>,
gvar_fragments: Arc<RwLock<HashMap<GlyphName, Arc<GvarFragment>>>>,

glyf_loca: ContextItem<GlyfLoca>,
avar: ContextItem<Avar>,
cmap: ContextItem<Cmap>,
fvar: ContextItem<Fvar>,
gsub: ContextItem<Gsub>,
gpos: ContextItem<Gpos>,
gvar: ContextItem<Bytes>,
post: ContextItem<Post>,
loca_format: ContextItem<LocaFormat>,
Expand All @@ -374,13 +378,14 @@ impl Context {
paths: self.paths.clone(),
ir: self.ir.clone(),
acl,
features: self.features.clone(),
glyphs: self.glyphs.clone(),
gvar_fragments: self.gvar_fragments.clone(),
glyf_loca: self.glyf_loca.clone(),
avar: self.avar.clone(),
cmap: self.cmap.clone(),
fvar: self.fvar.clone(),
gsub: self.gsub.clone(),
gpos: self.gpos.clone(),
gvar: self.gvar.clone(),
post: self.post.clone(),
loca_format: self.loca_format.clone(),
Expand All @@ -400,13 +405,14 @@ impl Context {
paths: Arc::from(paths),
ir: Arc::from(ir.read_only()),
acl: AccessControlList::read_only(),
features: Arc::from(RwLock::new(None)),
glyphs: Arc::from(RwLock::new(HashMap::new())),
gvar_fragments: Arc::from(RwLock::new(HashMap::new())),
glyf_loca: Arc::from(RwLock::new(None)),
avar: Arc::from(RwLock::new(None)),
cmap: Arc::from(RwLock::new(None)),
fvar: Arc::from(RwLock::new(None)),
gpos: Arc::from(RwLock::new(None)),
gsub: Arc::from(RwLock::new(None)),
gvar: Arc::from(RwLock::new(None)),
post: Arc::from(RwLock::new(None)),
loca_format: Arc::from(RwLock::new(None)),
Expand Down Expand Up @@ -437,13 +443,6 @@ impl Context {
self.paths.debug_dir()
}

fn maybe_persist(&self, file: &Path, content: &[u8]) {
if !self.flags.contains(Flags::EMIT_IR) {
return;
}
self.persist(file, content);
}

// we need a self.persist for macros
fn persist(&self, file: &Path, content: &[u8]) {
persist(file, content);
Expand All @@ -454,29 +453,6 @@ impl Context {
fs::read(self.paths.target_file(&id))
}

pub fn get_features(&self) -> Arc<Vec<u8>> {
let id = WorkId::Features;
self.acl.assert_read_access(&id.clone().into());
{
let rl = self.features.read();
if rl.is_some() {
return rl.as_ref().unwrap().clone();
}
}
let font = read_entire_file(&self.paths.target_file(&id));
set_cached(&self.features, font);
let rl = self.features.read();
rl.as_ref().expect(MISSING_DATA).clone()
}

pub fn set_features(&self, mut font: FontBuilder) {
let id = WorkId::Features;
self.acl.assert_write_access(&id.clone().into());
let font = font.build();
self.maybe_persist(&self.paths.target_file(&id), &font);
set_cached(&self.features, font);
}

fn set_cached_glyph(&self, glyph_name: GlyphName, glyph: Glyph) {
let mut wl = self.glyphs.write();
wl.insert(glyph_name, Arc::from(glyph));
Expand Down Expand Up @@ -568,6 +544,23 @@ impl Context {
rl.as_ref().expect(MISSING_DATA).clone()
}

pub fn has_glyf_loca(&self) -> bool {
let ids = [
WorkId::Glyf.into(),
WorkId::Loca.into(),
WorkId::LocaFormat.into(),
];
self.acl.assert_read_access_to_all(&ids);
{
let rl = self.glyf_loca.read();
if rl.is_some() {
return true;
}
}
ids.iter()
.all(|id| self.paths.target_file(id.unwrap_be()).is_file())
}

pub fn set_glyf_loca(&self, glyf_loca: GlyfLoca) {
let ids = [
WorkId::Glyf.into(),
Expand All @@ -586,21 +579,23 @@ impl Context {
}

// Lovely little typed accessors
context_accessors! { get_avar, set_avar, avar, Avar, WorkId::Avar, from_file, to_bytes }
context_accessors! { get_cmap, set_cmap, cmap, Cmap, WorkId::Cmap, from_file, to_bytes }
context_accessors! { get_fvar, set_fvar, fvar, Fvar, WorkId::Fvar, from_file, to_bytes }
context_accessors! { get_loca_format, set_loca_format, loca_format, LocaFormat, WorkId::LocaFormat, loca_format_from_file, loca_format_to_bytes }
context_accessors! { get_maxp, set_maxp, maxp, Maxp, WorkId::Maxp, from_file, to_bytes }
context_accessors! { get_name, set_name, name, Name, WorkId::Name, from_file, to_bytes }
context_accessors! { get_os2, set_os2, os2, Os2, WorkId::Os2, from_file, to_bytes }
context_accessors! { get_post, set_post, post, Post, WorkId::Post, from_file, to_bytes }
context_accessors! { get_head, set_head, head, Head, WorkId::Head, from_file, to_bytes }
context_accessors! { get_hhea, set_hhea, hhea, Hhea, WorkId::Hhea, from_file, to_bytes }
context_accessors! { get_avar, set_avar, has_avar, avar, Avar, WorkId::Avar, from_file, to_bytes }
context_accessors! { get_cmap, set_cmap, has_cmap, cmap, Cmap, WorkId::Cmap, from_file, to_bytes }
context_accessors! { get_fvar, set_fvar, has_fvar, fvar, Fvar, WorkId::Fvar, from_file, to_bytes }
context_accessors! { get_loca_format, set_loca_format, has_loca_format, loca_format, LocaFormat, WorkId::LocaFormat, loca_format_from_file, loca_format_to_bytes }
context_accessors! { get_maxp, set_maxp, has_maxp, maxp, Maxp, WorkId::Maxp, from_file, to_bytes }
context_accessors! { get_name, set_name, has_name, name, Name, WorkId::Name, from_file, to_bytes }
context_accessors! { get_os2, set_os2, has_os2, os2, Os2, WorkId::Os2, from_file, to_bytes }
context_accessors! { get_post, set_post, has_post, post, Post, WorkId::Post, from_file, to_bytes }
context_accessors! { get_head, set_head, has_head, head, Head, WorkId::Head, from_file, to_bytes }
context_accessors! { get_hhea, set_hhea, has_hhea, hhea, Hhea, WorkId::Hhea, from_file, to_bytes }
context_accessors! { get_gpos, set_gpos, has_gpos, gpos, Gpos, WorkId::Gpos, from_file, to_bytes }
context_accessors! { get_gsub, set_gsub, has_gsub, gsub, Gsub, WorkId::Gsub, from_file, to_bytes }

// Accessors where value is raw bytes
context_accessors! { get_gvar, set_gvar, gvar, Bytes, WorkId::Gvar, raw_from_file, raw_to_bytes }
context_accessors! { get_hmtx, set_hmtx, hmtx, Bytes, WorkId::Hmtx, raw_from_file, raw_to_bytes }
context_accessors! { get_font, set_font, font, Bytes, WorkId::Font, raw_from_file, raw_to_bytes }
context_accessors! { get_gvar, set_gvar, has_gvar, gvar, Bytes, WorkId::Gvar, raw_from_file, raw_to_bytes }
context_accessors! { get_hmtx, set_hmtx, has_hmtx, hmtx, Bytes, WorkId::Hmtx, raw_from_file, raw_to_bytes }
context_accessors! { get_font, set_font, has_font, font, Bytes, WorkId::Font, raw_from_file, raw_to_bytes }
}

fn set_cached<T>(lock: &Arc<RwLock<Option<Arc<T>>>>, value: T) {
Expand Down
4 changes: 3 additions & 1 deletion fontbe/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,13 @@ impl Paths {

pub fn target_file(&self, id: &WorkId) -> PathBuf {
match id {
WorkId::Features => self.build_dir.join("features.ttf"),
WorkId::Features => self.build_dir.join("features.marker"),
WorkId::GlyfFragment(name) => self.glyph_glyf_file(name.as_str()),
WorkId::GvarFragment(name) => self.glyph_gvar_file(name.as_str()),
WorkId::Avar => self.build_dir.join("avar.table"),
WorkId::Glyf => self.build_dir.join("glyf.table"),
WorkId::Gsub => self.build_dir.join("gsub.table"),
WorkId::Gpos => self.build_dir.join("gpos.table"),
WorkId::Gvar => self.build_dir.join("gvar.table"),
WorkId::Loca => self.build_dir.join("loca.table"),
WorkId::LocaFormat => self.build_dir.join("loca.format"),
Expand Down
Loading

0 comments on commit f62b28e

Please sign in to comment.