167 lines
5.2 KiB
Rust

use allsorts::{
binary::read::ReadScope,
font::{Font, MatchingPresentation},
font_data::FontData as AllsortsFontData,
subset::subset,
tag,
};
use epaint::{
text::{FontData, FontDefinitions, FontTweak},
FontFamily,
};
use std::{
collections::BTreeMap,
env,
fs::File,
io::{BufWriter, Write},
path::Path,
sync::Arc,
};
include!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/src/unicode_helper.rs"
));
fn font_stripper(from: &str, out: &str, unicodes: Vec<char>) -> Result<Vec<u8>, String> {
let font_path = format!("{}/assets/{}", env!("CARGO_MANIFEST_DIR"), from);
let font_data = std::fs::read(&font_path).map_err(|e| e.to_string())?;
let scope = ReadScope::new(&font_data);
let font_file = scope
.read::<AllsortsFontData>()
.map_err(|e| format!("Failed to read font data: {}", e))?;
let provider = font_file
.table_provider(0)
.map_err(|e| format!("Failed to get table provider: {}", e))?;
let mut font = Font::new(provider).map_err(|e| format!("Failed to create font: {:?}", e))?;
let mut glyph_ids = Vec::new();
for &ch in &unicodes {
let mut glyph_ids_curr = font
.map_glyphs(
&ch.to_string(),
tag::LATN,
MatchingPresentation::NotRequired,
)
.into_iter()
.map(|glyph| glyph.glyph_index)
.collect();
glyph_ids.append(&mut glyph_ids_curr);
}
// Include .notdef glyph
glyph_ids.push(0);
glyph_ids.sort();
glyph_ids.dedup();
let subset_data = subset(&font.font_table_provider, &glyph_ids)
.map_err(|e| format!("Failed to subset font: {}", e))?;
let new_path = [&env::var("OUT_DIR").unwrap(), out].concat();
std::fs::write(&new_path, &subset_data)
.map_err(|e| format!("Failed to write subset font: {}", e))?;
Ok(subset_data)
}
fn main() {
// rebuild if contents of `assets` folder changed
println!("cargo:rerun-if-changed=assets/*");
let mut main_chars: Vec<char> =
b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzsu0123456789?.,!(){}[]-_=+-/<>'\\ :^*`@#$%&|~;"
.iter()
.map(|c| *c as char)
.collect();
main_chars.append(&mut vec!['π', '"']);
{
let filtered_chars: Vec<char> = main_chars
.iter()
.filter(|c| !c.is_alphanumeric())
.cloned()
.collect();
let chars_array = format!(
"const VALID_EXTRA_CHARS: [char; {}] = {};",
filtered_chars.len(),
to_chars_array(filtered_chars),
);
let path = Path::new(&env::var("OUT_DIR").unwrap()).join("valid_chars.rs");
let mut file = BufWriter::new(File::create(path).expect("Could not save compressed_data"));
write!(&mut file, "{}", chars_array).expect("unable to write chars_array");
}
let fonts = FontDefinitions {
font_data: BTreeMap::from([
(
"Ubuntu-Light".to_owned(),
Arc::new(FontData::from_owned(
font_stripper(
"Ubuntu-Light.ttf",
"ubuntu-light.ttf",
[main_chars, vec!['∫']].concat(),
)
.unwrap(),
)),
),
(
"NotoEmoji-Regular".to_owned(),
Arc::new(FontData::from_owned(
font_stripper(
"NotoEmoji-Regular.ttf",
"noto-emoji.ttf",
vec!['🌞', '🌙', '✖'],
)
.unwrap(),
)),
),
(
"emoji-icon-font".to_owned(),
Arc::new(
FontData::from_owned(
font_stripper("emoji-icon-font.ttf", "emoji-icon.ttf", vec!['⚙']).unwrap(),
)
.tweak(FontTweak {
scale: 0.8,
y_offset_factor: 0.07,
y_offset: -0.0333,
}),
),
),
]),
families: BTreeMap::from([
(
FontFamily::Monospace,
vec![
"Ubuntu-Light".to_owned(),
"NotoEmoji-Regular".to_owned(),
"emoji-icon-font".to_owned(),
],
),
(
FontFamily::Proportional,
vec![
"Ubuntu-Light".to_owned(),
"NotoEmoji-Regular".to_owned(),
"emoji-icon-font".to_owned(),
],
),
]),
};
let data = bincode::serialize(&fonts).unwrap();
let zstd_levels = zstd::compression_level_range();
let data_compressed =
zstd::encode_all(data.as_slice(), *zstd_levels.end()).expect("Could not compress data");
let path = Path::new(&env::var("OUT_DIR").unwrap()).join("compressed_data");
let mut file = BufWriter::new(File::create(path).expect("Could not save compressed_data"));
file.write_all(data_compressed.as_slice())
.expect("Failed to save compressed data");
}