From fa1a32bdbb3faf6a81fda219e0104036ff0f772f Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 27 Jul 2019 06:02:20 +0200 Subject: [PATCH] Make text rendering optional in pathfinder_canvas --- c/Cargo.toml | 1 + canvas/Cargo.toml | 7 +- canvas/src/lib.rs | 258 +++++++++++++---------- examples/canvas_metal_minimal/Cargo.toml | 1 + examples/canvas_moire/Cargo.toml | 1 + examples/canvas_text/Cargo.toml | 1 + 6 files changed, 154 insertions(+), 115 deletions(-) diff --git a/c/Cargo.toml b/c/Cargo.toml index e1c0eb0b..e454352d 100644 --- a/c/Cargo.toml +++ b/c/Cargo.toml @@ -15,6 +15,7 @@ gl = "0.6" libc = "0.2" [dependencies.pathfinder_canvas] +features = ["text"] path = "../canvas" [dependencies.pathfinder_content] diff --git a/canvas/Cargo.toml b/canvas/Cargo.toml index fb4f8037..5bd59f9a 100644 --- a/canvas/Cargo.toml +++ b/canvas/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["rlib", "staticlib"] [dependencies] -font-kit = "0.2" +font-kit = { version = "0.2", optional = true } [dependencies.pathfinder_content] path = "../content" @@ -21,7 +21,12 @@ path = "../renderer" [dependencies.pathfinder_text] path = "../text" +optional = true [dependencies.skribo] git = "https://github.com/linebender/skribo.git" rev = "a2d683856ba1f2d0095b12dd7823d1602a87614e" +optional = true + +[features] +text = ["pathfinder_text", "skribo", "font-kit"] diff --git a/canvas/src/lib.rs b/canvas/src/lib.rs index 013203b1..03f89997 100644 --- a/canvas/src/lib.rs +++ b/canvas/src/lib.rs @@ -10,13 +10,6 @@ //! A simple API for Pathfinder that mirrors a subset of HTML canvas. -use font_kit::family_name::FamilyName; -use font_kit::handle::Handle; -use font_kit::hinting::HintingOptions; -use font_kit::loaders::default::Font; -use font_kit::properties::Properties; -use font_kit::source::{Source, SystemSource}; -use font_kit::sources::mem::MemSource; use pathfinder_content::color::ColorU; use pathfinder_content::dash::OutlineDash; use pathfinder_content::outline::{ArcDirection, Contour, Outline}; @@ -28,17 +21,33 @@ use pathfinder_geometry::rect::RectF; use pathfinder_geometry::transform2d::Transform2F; use pathfinder_renderer::paint::{Paint, PaintId}; use pathfinder_renderer::scene::{PathObject, Scene}; -use pathfinder_text::{SceneExt, TextRenderMode}; -use skribo::{FontCollection, FontFamily, Layout, TextStyle}; use std::default::Default; use std::f32::consts::PI; -use std::iter; use std::mem; use std::sync::Arc; +#[cfg(feature = "text")] +use text_imports::*; const HAIRLINE_STROKE_WIDTH: f32 = 0.0333; const DEFAULT_FONT_SIZE: f32 = 10.0; +#[cfg(feature = "text")] +mod text_imports { + pub use std::iter; + pub use font_kit::family_name::FamilyName; + pub use font_kit::handle::Handle; + pub use font_kit::hinting::HintingOptions; + pub use font_kit::loaders::default::Font; + pub use font_kit::properties::Properties; + pub use font_kit::source::{Source, SystemSource}; + pub use font_kit::sources::mem::MemSource; + pub use skribo::{FontCollection, FontFamily, Layout, TextStyle}; + pub use pathfinder_text::{SceneExt, TextRenderMode}; +} + +#[cfg(not(feature = "text"))] +pub struct FontCollection; + pub struct CanvasRenderingContext2D { scene: Scene, current_state: State, @@ -56,9 +65,13 @@ impl CanvasRenderingContext2D { } pub fn from_scene(font_context: CanvasFontContext, scene: Scene) -> CanvasRenderingContext2D { + #[cfg(feature = "text")] + let default_font_collection = font_context.default_font_collection.clone(); + #[cfg(not(feature = "text"))] + let default_font_collection = Arc::new(FontCollection); CanvasRenderingContext2D { scene, - current_state: State::default(font_context.default_font_collection.clone()), + current_state: State::default(default_font_collection), saved_states: vec![], font_context, } @@ -85,63 +98,6 @@ impl CanvasRenderingContext2D { self.stroke_path(path); } - // Drawing text - - pub fn fill_text(&mut self, string: &str, position: Vector2F) { - let paint_id = self.scene.push_paint(&self.current_state.fill_paint); - self.fill_or_stroke_text(string, position, paint_id, TextRenderMode::Fill); - } - - pub fn stroke_text(&mut self, string: &str, position: Vector2F) { - let paint_id = self.scene.push_paint(&self.current_state.stroke_paint); - let render_mode = TextRenderMode::Stroke(self.current_state.resolve_stroke_style()); - self.fill_or_stroke_text(string, position, paint_id, render_mode); - } - - pub fn measure_text(&self, string: &str) -> TextMetrics { - TextMetrics { width: self.layout_text(string).width() } - } - - pub fn fill_layout(&mut self, layout: &Layout, transform: Transform2F) { - let paint_id = self.scene.push_paint(&self.current_state.fill_paint); - drop(self.scene.push_layout(&layout, - &TextStyle { size: self.current_state.font_size }, - &(transform * self.current_state.transform), - TextRenderMode::Fill, - HintingOptions::None, - paint_id)); - } - - fn fill_or_stroke_text(&mut self, - string: &str, - mut position: Vector2F, - paint_id: PaintId, - render_mode: TextRenderMode) { - let layout = self.layout_text(string); - - match self.current_state.text_align { - TextAlign::Left => {}, - TextAlign::Right => position.set_x(position.x() - layout.width()), - TextAlign::Center => position.set_x(position.x() - layout.width() * 0.5), - } - - let transform = self.current_state.transform * Transform2F::from_translation(position); - - // TODO(pcwalton): Report errors. - drop(self.scene.push_layout(&layout, - &TextStyle { size: self.current_state.font_size }, - &transform, - render_mode, - HintingOptions::None, - paint_id)); - } - - fn layout_text(&self, string: &str) -> Layout { - skribo::layout(&TextStyle { size: self.current_state.font_size }, - &self.current_state.font_collection, - string) - } - // Line styles #[inline] @@ -181,52 +137,6 @@ impl CanvasRenderingContext2D { self.current_state.line_dash_offset = new_line_dash_offset } - // Text styles - - #[inline] - pub fn set_font_collection(&mut self, font_collection: Arc) { - self.current_state.font_collection = font_collection; - } - - #[inline] - pub fn set_font_families(&mut self, font_families: I) where I: Iterator { - let mut font_collection = FontCollection::new(); - for font_family in font_families { - font_collection.add_family(font_family); - } - self.current_state.font_collection = Arc::new(font_collection); - } - - /// A convenience method to set a single font family. - #[inline] - pub fn set_font_family(&mut self, font_family: FontFamily) { - self.set_font_families(iter::once(font_family)) - } - - /// A convenience method to set a single font family consisting of a single font. - #[inline] - pub fn set_font(&mut self, font: Font) { - self.set_font_family(FontFamily::new_from_font(font)) - } - - /// A convenience method to set a single font family consisting of a font - /// described by a PostScript name. - #[inline] - pub fn set_font_by_postscript_name(&mut self, postscript_name: &str) { - let font = self.font_context.font_source.select_by_postscript_name(postscript_name); - self.set_font(font.expect("Didn't find the font!").load().unwrap()); - } - - #[inline] - pub fn set_font_size(&mut self, new_font_size: f32) { - self.current_state.font_size = new_font_size; - } - - #[inline] - pub fn set_text_align(&mut self, new_text_align: TextAlign) { - self.current_state.text_align = new_text_align; - } - // Fill and stroke styles #[inline] @@ -346,6 +256,111 @@ impl CanvasRenderingContext2D { } } +// Drawing text +#[cfg(feature = "text")] +impl CanvasRenderingContext2D { + pub fn fill_text(&mut self, string: &str, position: Vector2F) { + let paint_id = self.scene.push_paint(&self.current_state.fill_paint); + self.fill_or_stroke_text(string, position, paint_id, TextRenderMode::Fill); + } + + pub fn stroke_text(&mut self, string: &str, position: Vector2F) { + let paint_id = self.scene.push_paint(&self.current_state.stroke_paint); + let render_mode = TextRenderMode::Stroke(self.current_state.resolve_stroke_style()); + self.fill_or_stroke_text(string, position, paint_id, render_mode); + } + + pub fn measure_text(&self, string: &str) -> TextMetrics { + TextMetrics { width: self.layout_text(string).width() } + } + + pub fn fill_layout(&mut self, layout: &Layout, transform: Transform2F) { + let paint_id = self.scene.push_paint(&self.current_state.fill_paint); + drop(self.scene.push_layout(&layout, + &TextStyle { size: self.current_state.font_size }, + &(transform * self.current_state.transform), + TextRenderMode::Fill, + HintingOptions::None, + paint_id)); + } + + fn fill_or_stroke_text(&mut self, + string: &str, + mut position: Vector2F, + paint_id: PaintId, + render_mode: TextRenderMode) { + let layout = self.layout_text(string); + + match self.current_state.text_align { + TextAlign::Left => {}, + TextAlign::Right => position.set_x(position.x() - layout.width()), + TextAlign::Center => position.set_x(position.x() - layout.width() * 0.5), + } + + let transform = self.current_state.transform * Transform2F::from_translation(position); + + // TODO(pcwalton): Report errors. + drop(self.scene.push_layout(&layout, + &TextStyle { size: self.current_state.font_size }, + &transform, + render_mode, + HintingOptions::None, + paint_id)); + } + + fn layout_text(&self, string: &str) -> Layout { + skribo::layout(&TextStyle { size: self.current_state.font_size }, + &self.current_state.font_collection, + string) + } + + // Text styles + + #[inline] + pub fn set_font_collection(&mut self, font_collection: Arc) { + self.current_state.font_collection = font_collection; + } + + #[inline] + pub fn set_font_families(&mut self, font_families: I) where I: Iterator { + let mut font_collection = FontCollection::new(); + for font_family in font_families { + font_collection.add_family(font_family); + } + self.current_state.font_collection = Arc::new(font_collection); + } + + /// A convenience method to set a single font family. + #[inline] + pub fn set_font_family(&mut self, font_family: FontFamily) { + self.set_font_families(iter::once(font_family)) + } + + /// A convenience method to set a single font family consisting of a single font. + #[inline] + pub fn set_font(&mut self, font: Font) { + self.set_font_family(FontFamily::new_from_font(font)) + } + + /// A convenience method to set a single font family consisting of a font + /// described by a PostScript name. + #[inline] + pub fn set_font_by_postscript_name(&mut self, postscript_name: &str) { + let font = self.font_context.font_source.select_by_postscript_name(postscript_name); + self.set_font(font.expect("Didn't find the font!").load().unwrap()); + } + + #[inline] + pub fn set_font_size(&mut self, new_font_size: f32) { + self.current_state.font_size = new_font_size; + } + + #[inline] + pub fn set_text_align(&mut self, new_text_align: TextAlign) { + self.current_state.text_align = new_text_align; + } +} + #[derive(Clone)] struct State { transform: Transform2F, @@ -544,12 +559,14 @@ pub enum LineJoin { } // TODO(pcwalton): Support other fields. +#[cfg(feature = "text")] #[derive(Clone, Copy, Debug)] pub struct TextMetrics { pub width: f32, } #[derive(Clone)] +#[cfg(feature = "text")] pub struct CanvasFontContext { #[allow(dead_code)] font_source: Arc, @@ -557,6 +574,7 @@ pub struct CanvasFontContext { default_font_collection: Arc, } +#[cfg(feature = "text")] impl CanvasFontContext { pub fn new(font_source: Arc) -> CanvasFontContext { let mut default_font_collection = FontCollection::new(); @@ -585,12 +603,24 @@ impl CanvasFontContext { } } +#[cfg(not(feature = "text"))] +pub struct CanvasFontContext; + +#[cfg(not(feature = "text"))] +impl CanvasFontContext { + pub fn from_system_source() -> Self { + CanvasFontContext + } +} + // Text layout utilities +#[cfg(feature = "text")] trait LayoutExt { fn width(&self) -> f32; } +#[cfg(feature = "text")] impl LayoutExt for Layout { fn width(&self) -> f32 { let last_glyph = match self.glyphs.last() { diff --git a/examples/canvas_metal_minimal/Cargo.toml b/examples/canvas_metal_minimal/Cargo.toml index 74cfde80..b7ecdef1 100644 --- a/examples/canvas_metal_minimal/Cargo.toml +++ b/examples/canvas_metal_minimal/Cargo.toml @@ -13,6 +13,7 @@ sdl2 = "0.32" sdl2-sys = "0.32" [dependencies.pathfinder_canvas] +features = ["text"] path = "../../canvas" [dependencies.pathfinder_content] diff --git a/examples/canvas_moire/Cargo.toml b/examples/canvas_moire/Cargo.toml index cb8f98ea..b07b600d 100644 --- a/examples/canvas_moire/Cargo.toml +++ b/examples/canvas_moire/Cargo.toml @@ -10,6 +10,7 @@ sdl2 = "0.32" sdl2-sys = "0.32" [dependencies.pathfinder_canvas] +features = ["text"] path = "../../canvas" [dependencies.pathfinder_content] diff --git a/examples/canvas_text/Cargo.toml b/examples/canvas_text/Cargo.toml index 6250e71a..e3301e01 100644 --- a/examples/canvas_text/Cargo.toml +++ b/examples/canvas_text/Cargo.toml @@ -11,6 +11,7 @@ sdl2 = "0.32" sdl2-sys = "0.32" [dependencies.pathfinder_canvas] +features = ["text"] path = "../../canvas" [dependencies.pathfinder_content]