From 6177ddf0d7a84fd37628d9ab2acabbddf7136629 Mon Sep 17 00:00:00 2001 From: Monadic Cat Date: 2021年11月29日 07:23:27 -0600 Subject: [PATCH 1/2] preliminary work to add ab_glyph font backend --- Cargo.toml | 4 ++ src/style/font/ab_glyph.rs | 116 +++++++++++++++++++++++++++++++++++++ src/style/font/mod.rs | 11 +++- src/style/mod.rs | 3 + 4 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 src/style/font/ab_glyph.rs diff --git a/Cargo.toml b/Cargo.toml index 9296eef0..d22df00e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,8 @@ ttf-parser = { version = "0.12.0", optional = true } lazy_static = { version = "1.4.0", optional = true } pathfinder_geometry = { version = "0.5.1", optional = true } font-kit = { version = "0.10.0", optional = true } +ab_glyph = { version = "0.2.12", optional = true } +once_cell = { version = "1.8.0", optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies.image] version = "0.23.14" @@ -90,6 +92,8 @@ surface_series = [] # Font implemnetation ttf = ["font-kit", "ttf-parser", "lazy_static", "pathfinder_geometry"] +ab_glyph_ = ["ab_glyph", "once_cell"] + # Misc datetime = ["chrono"] evcxr = ["svg_backend"] diff --git a/src/style/font/ab_glyph.rs b/src/style/font/ab_glyph.rs new file mode 100644 index 00000000..aa087827 --- /dev/null +++ b/src/style/font/ab_glyph.rs @@ -0,0 +1,116 @@ +use super::{FontData, FontFamily, FontStyle, LayoutBox}; +use ::core::fmt::{self, Display}; +use ::std::error::Error; +use ::std::collections::HashMap; +use ::std::sync::RwLock; +use ::once_cell::sync::Lazy; +use ::ab_glyph::{FontRef, Font, ScaleFont}; + +static FONTS: Lazy>>> = Lazy::new(|| RwLock::new(HashMap::new())); +pub struct InvalidFont { + _priv: (), +} + +/// Register a font in the fonts table. +pub fn register_font(name: &str, bytes: &'static [u8]) -> Result<(), InvalidFont> { + let font = FontRef::try_from_slice(bytes).map_err(|_| InvalidFont { _priv: () })?; + let mut lock = FONTS.write().unwrap(); + lock.insert(name.to_string(), font); + Ok(()) +} + +#[derive(Clone)] +pub struct FontDataInternal { + font_ref: FontRef<'static> +} + +#[derive(Debug, Clone)] +pub enum FontError { + /// No idea what the problem is + Unknown, + /// No font data available for the requested family and style. + FontUnavailable, +} +impl Display for FontError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Since it makes literally no difference to how we'd format + // this, just delegate to the derived Debug formatter. + write!(f, "{:?}", self) + } +} +impl Error for FontError {} + +impl FontData for FontDataInternal { + // TODO: can we rename this to `Error`? + type ErrorType = FontError; + fn new(family: FontFamily<'_>, style: FontStyle) -> Result { + Ok(Self { + font_ref: FONTS.read().unwrap().get(family.as_str()).ok_or(FontError::FontUnavailable)?.clone() + }) + } + // TODO: ngl, it makes no sense that this uses the same error type as `new` + fn estimate_layout(&self, size: f64, text: &str) -> Result { + let pixel_per_em = size / 1.24; + let units_per_em = self.font_ref.units_per_em().unwrap(); + let font = self.font_ref.as_scaled(size as f32); + + let mut x_pixels = 0f32; + + let mut prev = None; + for c in text.chars() { + let glyph_id = font.glyph_id(c); + let size = font.h_advance(glyph_id); + x_pixels += size; + if let Some(pc) = prev { + x_pixels += font.kern(pc, glyph_id); + } + prev = Some(glyph_id); + } + + Ok(((0, 0), (x_pixels as i32, pixel_per_em as i32))) + } + fn draw Result<(), E>>( + &self, + pos: (i32, i32), + size: f64, + text: &str, + mut draw: DrawFunc, + ) -> Result, Self::ErrorType> { + let font = self.font_ref.as_scaled(size as f32); + let mut draw = |x: u32, y: u32, c| { + let (x, y) = (x as i32, y as i32); + let (base_x, base_y) = pos; + draw(base_x + x, base_y + y, c) + }; + let mut x_shift = 0f32; + let mut prev = None; + for c in text.chars() { + if let Some(pc) = prev { + x_shift += font.kern(font.glyph_id(pc), font.glyph_id(c)); + } + prev = Some(c); + let glyph = font.scaled_glyph(c); + if let Some(q) = font.outline_glyph(glyph) { + use ::std::panic::{self, AssertUnwindSafe}; + let rect = q.px_bounds(); + // Vertically center the things. + let y_shift = (size as f32 - rect.height()) / 2.0; + let y_shift = y_shift as u32; + let res = panic::catch_unwind(AssertUnwindSafe(|| { + q.draw(|x, y, c| { + if let Err(_) = draw(x + (x_shift as u32), y + y_shift, c) { + panic!("fail") + } + }); + })); + if let Err(_) = res { + return Err(FontError::Unknown) + } + x_shift += font.h_advance(font.glyph_id(c)); + } else { + x_shift += font.h_advance(font.glyph_id(c)); + } + } + Ok(Ok(())) + } +} diff --git a/src/style/font/mod.rs b/src/style/font/mod.rs index 99c3ca62..b5b63f7f 100644 --- a/src/style/font/mod.rs +++ b/src/style/font/mod.rs @@ -11,9 +11,16 @@ mod ttf; #[cfg(all(not(target_arch = "wasm32"), feature = "ttf"))] use ttf::FontDataInternal; -#[cfg(all(not(target_arch = "wasm32"), not(feature = "ttf")))] +#[cfg(all(not(target_arch = "wasm32"), feature = "ab_glyph_"))] +mod ab_glyph; +#[cfg(all(not(target_arch = "wasm32"), feature = "ab_glyph_"))] +use self::ab_glyph::FontDataInternal; +#[cfg(all(not(target_arch = "wasm32"), feature = "ab_glyph_"))] +pub use self::ab_glyph::register_font; + +#[cfg(all(not(target_arch = "wasm32"), not(feature = "ttf"), not(feature = "ab_glyph_")))] mod naive; -#[cfg(all(not(target_arch = "wasm32"), not(feature = "ttf")))] +#[cfg(all(not(target_arch = "wasm32"), not(feature = "ttf"), not(feature = "ab_glyph_")))] use naive::FontDataInternal; #[cfg(target_arch = "wasm32")] diff --git a/src/style/mod.rs b/src/style/mod.rs index 7d7c9ac3..34a8df4c 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -20,6 +20,9 @@ pub use colors::full_palette; pub use font::{ FontDesc, FontError, FontFamily, FontResult, FontStyle, FontTransform, IntoFont, LayoutBox, }; +#[cfg(all(not(target_arch = "wasm32"), feature = "ab_glyph_"))] +pub use font::register_font; + pub use shape::ShapeStyle; pub use size::{AsRelative, RelativeSize, SizeDesc}; pub use text::text_anchor; From 69e02d2a1ed97454021d3010fd3b9c55dfa41167 Mon Sep 17 00:00:00 2001 From: Hao Hou Date: 2022年6月25日 21:46:12 -0700 Subject: [PATCH 2/2] Replace the Cargo.toml and prepare to merge --- Cargo.toml | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1c1f359c..88b84c38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,123 @@ -[workspace] -members = ["plotters", "plotters-backend", "plotters-bitmap", "plotters-svg"] -default-members = ["plotters"] +[package] +name = "plotters" +version = "0.3.1" +authors = ["Hao Hou "] +edition = "2021" +license = "MIT" +description = "A Rust drawing library focus on data plotting for both WASM and native applications" +repository = "https://github.com/38/plotters" +homepage = "https://plotters-rs.github.io/" +keywords = ["WebAssembly", "Visualization", "Plotting", "Drawing"] +categories = ["visualization", "wasm"] +readme = "README.md" +exclude = ["doc-template", "plotters-doc-data"] +[dependencies] +num-traits = "0.2.14" +chrono = { version = "0.4.19", optional = true } + +[dependencies.plotters-backend] +path = "../plotters-backend" + +[dependencies.plotters-bitmap] +default_features = false +path = "../plotters-bitmap" +optional = true + +[dependencies.plotters-svg] +path = "../plotters-svg" +optional = true + +[target.'cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"))))'.dependencies] +ttf-parser = { version = "0.15.0", optional = true } +lazy_static = { version = "1.4.0", optional = true } +pathfinder_geometry = { version = "0.5.1", optional = true } +font-kit = { version = "0.11.0", optional = true } + +[target.'cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"))))'.dependencies.image] +version = "0.24.2" +optional = true +default-features = false +features = ["jpeg", "png", "bmp"] + +[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi")))'.dependencies.wasm-bindgen] +version = "0.2.62" + +[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi")))'.dependencies.web-sys] +version = "0.3.51" +features = [ + "Document", + "DomRect", + "Element", + "HtmlElement", + "Node", + "Window", + "HtmlCanvasElement", + "CanvasRenderingContext2d", +] + +[features] +default = [ + "bitmap_backend", "bitmap_encoder", "bitmap_gif", + "svg_backend", + "chrono", + "ttf", + "image", + "deprecated_items", "all_series", "all_elements", + "full_palette" +] +all_series = ["area_series", "line_series", "point_series", "surface_series"] +all_elements = ["errorbar", "candlestick", "boxplot", "histogram"] + +# Tier 1 Backends +bitmap_backend = ["plotters-bitmap", "ttf"] +bitmap_encoder = ["plotters-bitmap/image_encoder"] +bitmap_gif = ["plotters-bitmap/gif_backend"] +svg_backend = ["plotters-svg"] + +# Colors +full_palette = [] + +# Elements +errorbar = [] +candlestick = [] +boxplot = [] + +# Series +histogram = [] +area_series = [] +line_series = [] +point_series = [] +surface_series = [] + +# Font implementation +ttf = ["font-kit", "ttf-parser", "lazy_static", "pathfinder_geometry"] +# dlopen fontconfig C library at runtime instead of linking at build time +# Can be useful for cross compiling, especially considering fontconfig has lots of C dependencies +fontconfig-dlopen = ["font-kit/source-fontconfig-dlopen"] + +# Misc +datetime = ["chrono"] +evcxr = ["svg_backend"] +deprecated_items = [] # Keep some of the deprecated items for backward compatibility + +[dev-dependencies] +itertools = "0.10.0" +criterion = "0.3.4" +rayon = "1.5.1" +serde_json = "1.0.64" +serde = "1.0.126" +serde_derive = "1.0.126" + +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] +rand = "0.8.3" +rand_distr = "0.4.0" +rand_xorshift = "0.3.0" + +[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi")))'.dev-dependencies] +wasm-bindgen-test = "0.3.24" + +[[bench]] +name = "benchmark" +harness = false +path = "benches/main.rs"

AltStyle によって変換されたページ (->オリジナル) /