Skip to content

Commit

Permalink
WIPping
Browse files Browse the repository at this point in the history
  • Loading branch information
madig committed Jun 13, 2020
1 parent 4495d54 commit 3332bf6
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 17 deletions.
8 changes: 4 additions & 4 deletions examples/fontinfotest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ fn main() -> Result<(), Error> {
if let Some(value) = d.get("blueFuzz") {
fontinfo.postscript_blue_fuzz = Some(IntegerOrFloat::try_from(value)?)
}
// if let Some(value) = d.get("blueScale") {
// fontinfo.postscript_blue_scale =
// Some(IntegerOrFloat::try_from(value).unwrap())
// }
// if let Some(value) = d.get("blueScale") {
// fontinfo.postscript_blue_scale =
// Some(IntegerOrFloat::try_from(value).unwrap())
// }
// use serde to do all this?
} else {
// error
Expand Down
25 changes: 25 additions & 0 deletions examples/plisttest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,36 @@ fn main() -> Result<(), Error> {

let lib_data: LibData =
plist::from_file(file_path).map_err(|e| Error::Custom(format!("{}", e)))?;

println!("{:?}", lib_data);
let ttt: Vec<IntegerOrFloat> =
lib_data.ps_hinting_data.unwrap().blue_values.unwrap().into_iter().flatten().collect();
println!("{:?}", ttt);

// convert features
let mut feature_text = String::new();

if let Some(feature_classes) = lib_data.feature_classes {
feature_text.push_str(&feature_classes);
}

if let Some(features) = lib_data.features {
let order: Vec<String> = if let Some(feature_order) = lib_data.feature_order {
feature_order
} else {
features.keys().cloned().collect::<Vec<String>>()
};

for key in order {
// Ignore non-existant keys because defcon does it, too.
if let Some(txt) = features.get(&key) {
feature_text.push_str(&txt);
}
}
}

println!("{}", feature_text);

Ok(())
}

Expand Down
41 changes: 28 additions & 13 deletions src/ufo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::fontinfo::FontInfo;
use crate::glyph::{Glyph, GlyphName};
use crate::layer::Layer;
use crate::names::NameList;
use crate::upconversion::upconvert_kerning;
use crate::upconversion;
use crate::Error;

static LAYER_CONTENTS_FILE: &str = "layercontents.plist";
Expand Down Expand Up @@ -134,32 +134,25 @@ impl Ufo {
let mut meta: MetaInfo = plist::from_file(meta_path)?;

let fontinfo_path = path.join(FONTINFO_FILE);
let font_info = if fontinfo_path.exists() {
let mut font_info = if fontinfo_path.exists() {
let font_info: FontInfo = FontInfo::from_file(fontinfo_path, meta.format_version)?;
Some(font_info)
} else {
None
};

let lib_path = path.join(LIB_FILE);
let lib = if lib_path.exists() {
let mut lib = if lib_path.exists() {
// Value::as_dictionary(_mut) will only borrow the data, but we want to own it.
// https://github.com/ebarnard/rust-plist/pull/48
match plist::Value::from_file(lib_path)? {
match plist::Value::from_file(&lib_path)? {
plist::Value::Dictionary(dict) => Some(dict),
_ => return Err(Error::ExpectedPlistDictionaryError),
}
} else {
None
};

// The v1 format stores some Postscript hinting related data in the lib,
// which we only import into fontinfo if we're reading a v1 UFO.
if meta.format_version == FormatVersion::V1 {
// TODO if no fontinfo.plist but stuff in lib.plist, create new fontinfo
todo!();
}

let groups_path = path.join(GROUPS_FILE);
let groups = if groups_path.exists() {
let groups: Groups = plist::from_file(groups_path)?;
Expand All @@ -178,7 +171,7 @@ impl Ufo {
};

let features_path = path.join(FEATURES_FILE);
let features = if features_path.exists() {
let mut features = if features_path.exists() {
let features = fs::read_to_string(features_path)?;
Some(features)
} else {
Expand Down Expand Up @@ -212,12 +205,34 @@ impl Ufo {
(_, None, k) => (None, k), // Without a groups.plist, there's nothing to upgrade.
(_, Some(g), k) => {
let (groups, kerning) =
upconvert_kerning(&g, &k.unwrap_or_default(), &glyph_names);
upconversion::upconvert_kerning(&g, &k.unwrap_or_default(), &glyph_names);
validate_groups(&groups).map_err(Error::GroupsUpconversionError)?;
(Some(groups), Some(kerning))
}
};

// The v1 format stores some Postscript hinting related data in the lib,
// which we only import into fontinfo if we're reading a v1 UFO.
if meta.format_version == FormatVersion::V1 {
let mut feature_text = String::new();
let mut fi =
if let Some(fontinfo) = font_info { fontinfo } else { FontInfo::default() };

if let Some(lib_data) = &mut lib {
upconversion::upconvert_ufov1_robofab_data(
&lib_path,
lib_data,
&mut feature_text,
&mut fi,
)?;
}

if !feature_text.is_empty() {
features = Some(feature_text);
}
font_info = Some(fi);
}

meta.format_version = FormatVersion::V3;

Ok(Ufo {
Expand Down
95 changes: 95 additions & 0 deletions src/upconversion.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::collections::{BTreeMap, HashMap, HashSet};

use crate::fontinfo::FontInfo;
use crate::names::NameList;
use crate::shared_types::IntegerOrFloat;
use crate::ufo::{Groups, Kerning};
use crate::Error;

/// Convert kerning groups and pairs from v1 and v2 informal conventions to v3 formal conventions.
/// Converted groups are added (duplicated) rather than replacing the old ones to preserve all data
Expand Down Expand Up @@ -104,6 +107,98 @@ fn find_known_kerning_groups(groups: &Groups) -> (HashSet<String>, HashSet<Strin
(groups_first, groups_second)
}

pub(crate) fn upconvert_ufov1_robofab_data(
lib_path: &std::path::PathBuf,
lib: &mut plist::Dictionary,
features: &mut String,
fontinfo: &mut FontInfo,
) -> Result<(), Error> {
#[derive(Debug, Deserialize)]
struct LibData {
#[serde(rename = "org.robofab.postScriptHintData")]
ps_hinting_data: Option<PsHintingData>,

#[serde(rename = "org.robofab.opentype.classes")]
feature_classes: Option<String>,
#[serde(rename = "org.robofab.opentype.featureorder")]
feature_order: Option<Vec<String>>,
#[serde(rename = "org.robofab.opentype.features")]
features: Option<HashMap<String, String>>,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct PsHintingData {
blue_fuzz: Option<IntegerOrFloat>,
blue_scale: Option<f64>,
blue_shift: Option<IntegerOrFloat>,
blue_values: Option<Vec<Vec<IntegerOrFloat>>>,
family_blues: Option<Vec<Vec<IntegerOrFloat>>>,
family_other_blues: Option<Vec<Vec<IntegerOrFloat>>>,
force_bold: Option<bool>,
other_blues: Option<Vec<Vec<IntegerOrFloat>>>,
stem_snap_h: Option<Vec<IntegerOrFloat>>,
stem_snap_v: Option<Vec<IntegerOrFloat>>,
}

// Reead lib.plist again because it is easier than pulling out the data manually.
let lib_data: LibData = plist::from_file(lib_path)?;

// Convert features.
features.clear();

if let Some(feature_classes) = lib_data.feature_classes {
features.push_str(&feature_classes);
}

if let Some(features_split) = lib_data.features {
let order: Vec<String> = if let Some(feature_order) = lib_data.feature_order {
feature_order
} else {
features_split.keys().cloned().collect::<Vec<String>>()
};

for key in order {
// Ignore non-existant keys because defcon does it, too.
if let Some(txt) = features_split.get(&key) {
features.push_str(&txt);
}
}
}

// Convert PostScript hinting data.
if let Some(ps_hinting_data) = lib_data.ps_hinting_data {
fontinfo.postscript_blue_fuzz = ps_hinting_data.blue_fuzz;
fontinfo.postscript_blue_scale = ps_hinting_data.blue_scale;
fontinfo.postscript_blue_shift = ps_hinting_data.blue_shift;
if let Some(blue_values) = ps_hinting_data.blue_values {
fontinfo.postscript_blue_values = Some(blue_values.into_iter().flatten().collect());
};
if let Some(other_blues) = ps_hinting_data.other_blues {
fontinfo.postscript_other_blues = Some(other_blues.into_iter().flatten().collect());
};
if let Some(family_blues) = ps_hinting_data.family_blues {
fontinfo.postscript_family_blues = Some(family_blues.into_iter().flatten().collect());
};
if let Some(family_other_blues) = ps_hinting_data.family_other_blues {
fontinfo.postscript_family_other_blues =
Some(family_other_blues.into_iter().flatten().collect());
};
fontinfo.postscript_force_bold = ps_hinting_data.force_bold;
fontinfo.postscript_stem_snap_h = ps_hinting_data.stem_snap_h;
fontinfo.postscript_stem_snap_v = ps_hinting_data.stem_snap_v;

fontinfo.validate()?;
}

lib.remove("org.robofab.postScriptHintData");
lib.remove("org.robofab.opentype.classes");
lib.remove("org.robofab.opentype.featureorder");
lib.remove("org.robofab.opentype.features");

Ok(())
}

#[cfg(test)]
mod tests {
extern crate maplit;
Expand Down

0 comments on commit 3332bf6

Please # to comment.