From ce3a1622bc6f0d1f7da90ffbc55b9db39ef18f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=80=E4=B8=9D?= Date: Sun, 6 Aug 2023 18:20:04 +0800 Subject: [PATCH] feat: Wasm --- __test__/wasm.spec.ts | 3 +- src/fonts.rs | 71 ++++++++++++++++++++++++++++++++++++------ wasm/index_bg.wasm | Bin 2043425 -> 2043443 bytes 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/__test__/wasm.spec.ts b/__test__/wasm.spec.ts index 7869ad79..d25859bc 100755 --- a/__test__/wasm.spec.ts +++ b/__test__/wasm.spec.ts @@ -330,7 +330,7 @@ test('should return undefined if bbox is invalid', (t) => { test('should render using font buffer provided by options', async (t) => { const svg = ` - Font Buffer + Font Buffer ` const pacificoBuffer = await fs.readFile(join(__dirname, './Pacifico-Regular.ttf')) @@ -339,7 +339,6 @@ test('should render using font buffer provided by options', async (t) => { const options = { font: { fontsBuffers: [pacificoBuffer], - loadSystemFonts: false, defaultFontFamily: 'Pacifico', }, } diff --git a/src/fonts.rs b/src/fonts.rs index 8bc40512..93516ebd 100644 --- a/src/fonts.rs +++ b/src/fonts.rs @@ -5,7 +5,6 @@ use crate::options::*; use resvg::usvg_text_layout::fontdb::{Database, Language}; - #[cfg(not(target_arch = "wasm32"))] use log::{debug, warn}; @@ -34,7 +33,7 @@ pub fn load_fonts(font_options: &JsFontOptions) -> Database { fontdb.load_fonts_dir(path); } - // 加载系统字体,Wasm 不支持 + // 加载系统字体 // https://github.com/RazrFalcon/fontdb/blob/052d74b9eb45f2c4f446846a53f33bd965e2662d/src/lib.rs#L261 if font_options.load_system_fonts { fontdb.load_system_fonts(); @@ -51,14 +50,14 @@ pub fn load_fonts(font_options: &JsFontOptions) -> Database { fontdb } -/// Loads fonts. +/// Loads fonts in Wasm. #[cfg(target_arch = "wasm32")] pub fn load_wasm_fonts( font_options: &JsFontOptions, fonts_buffers: Option, fontdb: &mut Database, ) -> Result<(), js_sys::Error> { - if let Some(fonts_buffers) = fonts_buffers { + if let Some(ref fonts_buffers) = fonts_buffers { for font in fonts_buffers.values().into_iter() { let raw_font = font?; let font_data = raw_font.dyn_into::()?.to_vec(); @@ -66,17 +65,23 @@ pub fn load_wasm_fonts( } } - set_font_families(font_options, fontdb); + set_wasm_font_families(font_options, fontdb, fonts_buffers); Ok(()) } +#[cfg(not(target_arch = "wasm32"))] fn set_font_families(font_options: &JsFontOptions, fontdb: &mut Database) { let mut default_font_family = font_options.default_font_family.clone(); // 当默认字体为空时,尝试直接从 font_files 中加载读取字体名称,然后设置到默认的 font-family 中 - if font_options.default_font_family.to_string().trim().is_empty() { - if font_options.font_files.len() > 0 || font_options.font_dirs.len() > 0 { + if font_options + .default_font_family + .to_string() + .trim() + .is_empty() + { + if font_options.font_files.len() > 0 || font_options.font_dirs.len() > 0 { for face in fontdb.faces() { // debug!("font_id = {}, post_script_name = {} ", face.id, face.post_script_name); @@ -91,12 +96,12 @@ fn set_font_families(font_options: &JsFontOptions, fontdb: &mut Database) { break; } - // 遍历所有加载的字体 // for face in fontdb.faces() { // if let Source::File(ref path) = &face.source { - // // 如果 path.display() 中包含了 font_options.font_files 中的字体路径,则设置为默认字体,并打印出 font_files 中的路径 - // // debug!("font_id = {}, post_script_name = {} ", face.id, face.post_script_name); + // // 如果 path.display() 中包含了 font_options.font_files + // 中的字体路径,则设置为默认字体,并打印出 font_files 中的路径 // + // debug!("font_id = {}, post_script_name = {} ", face.id, face.post_script_name); // // 匹配到 font_files 中的字体后,设置默认字体 // for font_file in &font_options.font_files { @@ -126,7 +131,53 @@ fn set_font_families(font_options: &JsFontOptions, fontdb: &mut Database) { // debug!("默认字体匹配到了 = {} ", default_font_family); // } // }); + } else { + default_font_family = "Arial".to_string(); + } + fontdb.set_serif_family(&default_font_family); + fontdb.set_sans_serif_family(&default_font_family); + fontdb.set_cursive_family(&default_font_family); + fontdb.set_fantasy_family(&default_font_family); + fontdb.set_monospace_family(&default_font_family); + } else { + fontdb.set_serif_family(&font_options.default_font_family); + fontdb.set_sans_serif_family(&font_options.default_font_family); + fontdb.set_cursive_family(&font_options.default_font_family); + fontdb.set_fantasy_family(&font_options.default_font_family); + fontdb.set_monospace_family(&font_options.default_font_family); + } + + #[cfg(not(target_arch = "wasm32"))] + find_and_debug_font_path(fontdb, default_font_family.as_str()) +} + +#[cfg(target_arch = "wasm32")] +fn set_wasm_font_families( + font_options: &JsFontOptions, + fontdb: &mut Database, + fonts_buffers: Option, +) { + let mut default_font_family = font_options.default_font_family.clone(); + + // 当默认字体为空时,尝试直接从 font_files 中加载读取字体名称,然后设置到默认的 font-family 中 + if font_options + .default_font_family + .to_string() + .trim() + .is_empty() + { + if let Some(_fonts_buffers) = fonts_buffers { + for face in fontdb.faces() { + let new_family = face + .families + .iter() + .find(|f| f.1 == Language::English_UnitedStates) + .unwrap_or(&face.families[0]); + + default_font_family = new_family.0.clone(); + break; + } } else { default_font_family = "Arial".to_string(); } diff --git a/wasm/index_bg.wasm b/wasm/index_bg.wasm index 56f6b11be00b8f5f21337a2270b00a454ab2013a..a3186fe06c6a301ad90b5897f98b6db68c19865b 100644 GIT binary patch delta 13211 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 m-s36!D)FnruR43)<27$wZ+{Cqd>;HaxX2%c% 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