Skip to content

Commit

Permalink
feat: add font resolve support and builder api
Browse files Browse the repository at this point in the history
  • Loading branch information
zimond committed Jun 17, 2022
1 parent 7e40b02 commit b2f667e
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 49 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ pathfinder_content = { version = "0.5.0", default-features = false }
pathfinder_simd = { version = "0.5.1", features = ["pf-no-simd"] }
futures = "0.3.21"
infer = "0.8.0"
ouroboros = "0.15.0"
roxmltree = "0.14.1"
fontkit = "0.1.0"

[target.'cfg(all(not(all(target_os = "linux", target_arch = "aarch64", target_env = "musl")), not(all(target_os = "windows", target_arch = "aarch64")), not(target_arch = "wasm32")))'.dependencies]
mimalloc-rust = { version = "0.1" }
Expand Down
102 changes: 102 additions & 0 deletions src/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use fontdb::Database;
use fontkit::FontKey;
#[cfg(not(target_arch = "wasm32"))]
use napi::bindgen_prelude::{Buffer, Either, Error as NapiError};
#[cfg(not(target_arch = "wasm32"))]
use napi_derive::napi;
use ouroboros::self_referencing;
use roxmltree::Document;

use crate::options::JsOptions;

#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
#[cfg_attr(not(target_arch = "wasm32"), napi)]
#[ouroboros::self_referencing]
pub struct ResvgBuilder {
font_db: fontdb::Database,
js_options: JsOptions,
data: String,
#[borrows(data)]
#[covariant]
doc: Document<'this>,
}

#[napi(js_name = "FontKey")]
pub struct FontKeyWrapper(FontKey);

#[cfg(not(target_arch = "wasm32"))]
#[napi]
impl ResvgBuilder {
#[napi(constructor)]
pub fn new_napi(
svg: Either<String, Buffer>,
options: Option<String>,
) -> Result<ResvgBuilder, NapiError> {
let js_options: JsOptions = options
.and_then(|o| serde_json::from_str(o.as_str()).ok())
.unwrap_or_default();
let _ = env_logger::builder()
.filter_level(js_options.log_level)
.try_init();
let mut opts = js_options.to_usvg_options();
crate::options::tweak_usvg_options(&mut opts);
let data = match svg {
Either::A(a) => a,
Either::B(b) => std::str::from_utf8(b.as_ref())
.map_err(|e| napi::Error::from_reason(format!("{}", e)))?
.to_string(),
};
ResvgBuilderTryBuilder {
font_db: Database::new(),
js_options,
data,
doc_builder: |input| Document::parse(input),
}
.try_build()
.map_err(|e| napi::Error::from_reason(format!("{}", e)))
}

#[napi]
pub fn texts_to_resolve(&self) -> Vec<FontKeyWrapper> {
vec![]
}

// fn new_inner(
// svg: &Either<String, Buffer>,
// options: Option<String>,
// ) -> Result<Resvg, NapiError> {
// let opts_ref = opts.to_ref();
// // Parse the SVG string into a tree.
// let tree = match svg {
// Either::A(a) => usvg::Tree::from_str(a.as_str(), &opts_ref),
// Either::B(b) => usvg::Tree::from_data(b.as_ref(), &opts_ref),
// }
// .map_err(|e| napi::Error::from_reason(format!("{}", e)))?;
// Ok(Resvg { tree, js_options })
// }
}

#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
impl ResvgBuilder {
#[wasm_bindgen(constructor)]
pub fn new(svg: IStringOrBuffer, options: Option<String>) -> Result<Resvg, js_sys::Error> {
let js_options: JsOptions = options
.and_then(|o| serde_json::from_str(o.as_str()).ok())
.unwrap_or_default();

let mut opts = js_options.to_usvg_options();
options::tweak_usvg_options(&mut opts);
let opts_ref = opts.to_ref();
let tree = if js_sys::Uint8Array::instanceof(&svg) {
let uintarray = js_sys::Uint8Array::unchecked_from_js_ref(&svg);
let svg_buffer = uintarray.to_vec();
usvg::Tree::from_data(&svg_buffer, &opts_ref).map_err(Error::from)
} else if let Some(s) = svg.as_string() {
usvg::Tree::from_str(s.as_str(), &opts_ref).map_err(Error::from)
} else {
Err(Error::InvalidInput)
}?;
Ok(Resvg { tree, js_options })
}
}
50 changes: 1 addition & 49 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use wasm_bindgen::{
JsCast,
};

mod builder;
mod error;
mod fonts;
mod options;
Expand Down Expand Up @@ -125,34 +126,6 @@ impl RenderedImage {
#[cfg(not(target_arch = "wasm32"))]
#[napi]
impl Resvg {
#[napi(constructor)]
pub fn new(svg: Either<String, Buffer>, options: Option<String>) -> Result<Resvg, NapiError> {
Resvg::new_inner(&svg, options)
}

fn new_inner(
svg: &Either<String, Buffer>,
options: Option<String>,
) -> Result<Resvg, NapiError> {
let js_options: JsOptions = options
.and_then(|o| serde_json::from_str(o.as_str()).ok())
.unwrap_or_default();
let _ = env_logger::builder()
.filter_level(js_options.log_level)
.try_init();

let mut opts = js_options.to_usvg_options();
options::tweak_usvg_options(&mut opts);
let opts_ref = opts.to_ref();
// Parse the SVG string into a tree.
let tree = match svg {
Either::A(a) => usvg::Tree::from_str(a.as_str(), &opts_ref),
Either::B(b) => usvg::Tree::from_data(b.as_ref(), &opts_ref),
}
.map_err(|e| napi::Error::from_reason(format!("{}", e)))?;
Ok(Resvg { tree, js_options })
}

#[napi]
/// Renders an SVG in Node.js
pub fn render(&self) -> Result<RenderedImage, NapiError> {
Expand Down Expand Up @@ -265,27 +238,6 @@ impl Resvg {
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
impl Resvg {
#[wasm_bindgen(constructor)]
pub fn new(svg: IStringOrBuffer, options: Option<String>) -> Result<Resvg, js_sys::Error> {
let js_options: JsOptions = options
.and_then(|o| serde_json::from_str(o.as_str()).ok())
.unwrap_or_default();

let mut opts = js_options.to_usvg_options();
options::tweak_usvg_options(&mut opts);
let opts_ref = opts.to_ref();
let tree = if js_sys::Uint8Array::instanceof(&svg) {
let uintarray = js_sys::Uint8Array::unchecked_from_js_ref(&svg);
let svg_buffer = uintarray.to_vec();
usvg::Tree::from_data(&svg_buffer, &opts_ref).map_err(Error::from)
} else if let Some(s) = svg.as_string() {
usvg::Tree::from_str(s.as_str(), &opts_ref).map_err(Error::from)
} else {
Err(Error::InvalidInput)
}?;
Ok(Resvg { tree, js_options })
}

/// Get the SVG width
#[wasm_bindgen(getter)]
pub fn width(&self) -> f64 {
Expand Down

0 comments on commit b2f667e

Please sign in to comment.