cn_font_split/
run_subset.rsuse crate::link_subset::name_template::name_template;
use crate::message::EventFactory;
use crate::runner::Context;
use cn_font_proto::api_interface::output_report::{
BundleMessage, SubsetDetail,
};
use cn_font_proto::api_interface::EventMessage;
use cn_font_utils::u8_size_in_kb;
use harfbuzz_rs_now::subset::Subset;
use harfbuzz_rs_now::{Face, Owned};
use log::{info, warn};
use rayon::iter::{
IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator,
};
use std::collections::BTreeSet;
use std::time::Instant;
use woff::version2::compress;
pub fn build_single_subset(face: &Owned<Face>, subset: &Vec<u32>) -> Vec<u8> {
let subset_runner = Subset::new();
subset_runner.clear_drop_table();
subset_runner.adjust_layout();
subset_runner.add_chars(subset);
let new_face = subset_runner.run_subset(&face).face_data();
let ttf_binary = new_face.get_data();
let woff2_binary = compress(ttf_binary, String::from(""), 1, true)
.expect("Failed to compress subset");
woff2_binary
}
struct ThreadResult {
pub subset_result: RunSubsetResult,
pub log: SubsetDetail,
pub message: EventMessage,
}
pub fn run_subset(ctx: &mut Context) {
let origin_bytes: u32 = (&ctx.input.input).len() as u32;
let all_chars = BTreeSet::from_iter(
ctx.face.collect_unicodes().iter().map(|x| x.clone()),
);
let origin_size: u32 = all_chars.len().try_into().unwrap();
let file_name_template = ctx.input.rename_output_font.clone();
info!("font subset result log");
let thread_result: Vec<ThreadResult> = ctx
.pre_subset_result
.par_iter()
.enumerate()
.map(|(index, r)| {
let start_time = Instant::now();
let result = build_single_subset(&ctx.face, r);
let result_bytes = u8_size_in_kb(&result);
let digest = md5::compute(result.as_slice());
let hash_string = format!("{:x}", digest);
let duration = start_time.elapsed();
info!(
"{}\t{}ms/{}/{}kb\t{}",
index,
duration.as_millis(),
r.len(),
result_bytes,
hash_string.to_string()
);
let file_name = if let Some(name) = &file_name_template {
name_template(&name, &hash_string, "woff2", &index)
} else {
hash_string.to_string() + ".woff2"
};
ThreadResult {
subset_result: RunSubsetResult {
hash: hash_string.to_string(),
unicodes: r.clone(),
file_name: file_name.clone(),
},
log: SubsetDetail {
id: (index as u32) + 1_u32,
file_name: file_name.clone(),
hash: hash_string.to_string(),
chars: r.clone(),
bytes: result.len() as u32,
duration: duration.as_millis() as u32,
},
message: EventMessage::output_data(&file_name, result),
}
})
.collect::<Vec<ThreadResult>>();
let mut bundled_bytes: u32 = 0;
let mut bundle_chars = BTreeSet::new();
bundle_chars.insert(0);
for res in thread_result {
(ctx.callback)(res.message);
bundled_bytes += res.log.bytes;
res.log.chars.iter().for_each(|x| {
bundle_chars.insert(x.clone());
});
ctx.run_subset_result.push(res.subset_result);
ctx.reporter.subset_detail.push(res.log);
}
let diff: Vec<u32> =
bundle_chars.difference(&all_chars).map(|x| x.clone()).collect();
if diff.len() > 0 {
warn!(
"subsets result diff: {}",
diff.iter()
.filter(|x| **x != 0)
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join(" ")
);
}
ctx.reporter.bundle_message = Some(BundleMessage {
origin_size,
bundled_size: bundle_chars.len() as u32,
origin_bytes,
bundled_bytes,
})
}
#[derive(Debug, Clone)]
pub struct RunSubsetResult {
pub hash: String,
pub unicodes: Vec<u32>,
pub file_name: String,
}