diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 37867434..8473ca2e 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -19,7 +19,7 @@ Examples: `Vec2, Pos2, Rect, lerp, remap` Example: `Shape::Circle { center, radius, fill, stroke }` -Depends on `emath`, [`rusttype`](https://crates.io/crates/rusttype), [`atomic_refcell`](https://crates.io/crates/atomic_refcell), [`ahash`](https://crates.io/crates/ahash). +Depends on `emath`, [`ab_glyph`](https://crates.io/crates/ab_glyph), [`atomic_refcell`](https://crates.io/crates/atomic_refcell), [`ahash`](https://crates.io/crates/ahash). ### `epi` Depends only on `egui`. diff --git a/Cargo.lock b/Cargo.lock index 63a88573..8e11e38d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,15 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "ab_glyph" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af0ac006645f86f20f6c6fa4dcaef920bf803df819123626f9440e35835e7d80" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser 0.12.0", +] + [[package]] name = "ab_glyph_rasterizer" version = "0.1.4" @@ -850,13 +860,13 @@ dependencies = [ name = "epaint" version = "0.12.0" dependencies = [ + "ab_glyph", "ahash", "atomic_refcell", "cint", "emath", "ordered-float", "parking_lot", - "rusttype", "serde", ] @@ -1721,7 +1731,16 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3" dependencies = [ - "ttf-parser", + "ttf-parser 0.6.2", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3c7a20e3f122223e68eef6ca58e39bc1ea8a1d83418ba4c2c1ba189d2ee355" +dependencies = [ + "ttf-parser 0.12.2", ] [[package]] @@ -2003,7 +2022,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59" dependencies = [ "ab_glyph_rasterizer", - "owned_ttf_parser", + "owned_ttf_parser 0.6.0", ] [[package]] @@ -2336,6 +2355,12 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" +[[package]] +name = "ttf-parser" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c56097738aec26a3f347edf99f5c84d9d4e3a4b8ce5513ebca85cb621fc7c50" + [[package]] name = "tts" version = "0.16.0" diff --git a/README.md b/README.md index 301b9a32..934ec477 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ ui.label(format!("Hello '{}', age {}", name, age)); * Extensible: [easy to write your own widgets for egui](https://github.com/emilk/egui/blob/master/egui_demo_lib/src/apps/demo/toggle_switch.rs) * Modular: You should be able to use small parts of egui and combine them in new ways * Safe: there is no `unsafe` code in egui -* Minimal dependencies: [`ahash`](https://crates.io/crates/ahash) [`atomic_refcell`](https://crates.io/crates/atomic_refcell) [`ordered-float`](https://crates.io/crates/ordered-float) [`rusttype`](https://crates.io/crates/rusttype). +* Minimal dependencies: [`ahash`](https://crates.io/crates/ahash) [`atomic_refcell`](https://crates.io/crates/atomic_refcell) [`ordered-float`](https://crates.io/crates/ordered-float) [`ab_glyph`](https://crates.io/crates/ab_glyph). egui is *not* a framework. egui is a library you call into, not an environment you program for. diff --git a/epaint/Cargo.toml b/epaint/Cargo.toml index 4bbb2c4b..81401529 100644 --- a/epaint/Cargo.toml +++ b/epaint/Cargo.toml @@ -24,12 +24,12 @@ include = [ [dependencies] emath = { version = "0.12.0", path = "../emath" } +ab_glyph = "0.2.11" ahash = { version = "0.7", features = ["std"], default-features = false } atomic_refcell = { version = "0.1", optional = true } # Used instead of parking_lot when you are always using epaint in a single thread. About as fast as parking_lot. Panics on multi-threaded use. cint = { version = "^0.2.2", optional = true } ordered-float = { version = "2", default-features = false } parking_lot = { version = "0.11", optional = true } # Using parking_lot over std::sync::Mutex gives 50% speedups in some real-world scenarios. -rusttype = "0.9" serde = { version = "1", features = ["derive"], optional = true } [features] diff --git a/epaint/src/text/font.rs b/epaint/src/text/font.rs index a43ae146..412796e6 100644 --- a/epaint/src/text/font.rs +++ b/epaint/src/text/font.rs @@ -1,10 +1,3 @@ -use std::sync::Arc; - -use { - ahash::AHashMap, - rusttype::{point, Scale}, -}; - use crate::{ mutex::{Mutex, RwLock}, text::{ @@ -13,7 +6,9 @@ use crate::{ }, TextureAtlas, }; +use ahash::AHashMap; use emath::{vec2, Vec2}; +use std::sync::Arc; // ---------------------------------------------------------------------------- @@ -32,7 +27,7 @@ pub struct UvRect { #[derive(Clone, Copy, Debug)] pub struct GlyphInfo { - id: rusttype::GlyphId, + id: ab_glyph::GlyphId, /// Unit: points. pub advance_width: f32, @@ -44,7 +39,7 @@ pub struct GlyphInfo { impl Default for GlyphInfo { fn default() -> Self { Self { - id: rusttype::GlyphId(0), + id: ab_glyph::GlyphId(0), advance_width: 0.0, uv_rect: None, } @@ -56,7 +51,7 @@ impl Default for GlyphInfo { /// A specific font with a size. /// The interface uses points as the unit for everything. pub struct FontImpl { - rusttype_font: Arc>, + ab_glyph_font: ab_glyph::FontArc, /// Maximum character height scale_in_pixels: f32, height_in_points: f32, @@ -71,7 +66,7 @@ impl FontImpl { pub fn new( atlas: Arc>, pixels_per_point: f32, - rusttype_font: Arc>, + ab_glyph_font: ab_glyph::FontArc, scale_in_points: f32, y_offset: f32, ) -> FontImpl { @@ -96,7 +91,7 @@ impl FontImpl { let y_offset = (y_offset * pixels_per_point).round() / pixels_per_point; Self { - rusttype_font, + ab_glyph_font, scale_in_pixels, height_in_points, y_offset, @@ -115,8 +110,9 @@ impl FontImpl { } // Add new character: - let glyph = self.rusttype_font.glyph(c); - if glyph.id().0 == 0 { + use ab_glyph::Font as _; + let glyph_id = self.ab_glyph_font.glyph_id(c); + if glyph_id.0 == 0 { if invisible_char(c) { // hack let glyph_info = GlyphInfo::default(); @@ -128,7 +124,8 @@ impl FontImpl { } else { let mut glyph_info = allocate_glyph( &mut self.atlas.lock(), - glyph, + &self.ab_glyph_font, + glyph_id, self.scale_in_pixels, self.y_offset, self.pixels_per_point, @@ -147,12 +144,13 @@ impl FontImpl { pub fn pair_kerning( &self, - last_glyph_id: rusttype::GlyphId, - glyph_id: rusttype::GlyphId, + last_glyph_id: ab_glyph::GlyphId, + glyph_id: ab_glyph::GlyphId, ) -> f32 { - let scale_in_pixels = Scale::uniform(self.scale_in_pixels); - self.rusttype_font - .pair_kerning(scale_in_pixels, last_glyph_id, glyph_id) + use ab_glyph::{Font as _, ScaleFont}; + self.ab_glyph_font + .as_scaled(self.scale_in_pixels) + .kern(last_glyph_id, glyph_id) / self.pixels_per_point } @@ -618,20 +616,22 @@ fn invisible_char(c: char) -> bool { fn allocate_glyph( atlas: &mut TextureAtlas, - glyph: rusttype::Glyph<'static>, + font: &ab_glyph::FontArc, + glyph_id: ab_glyph::GlyphId, scale_in_pixels: f32, y_offset: f32, pixels_per_point: f32, ) -> GlyphInfo { - assert!(glyph.id().0 != 0); + assert!(glyph_id.0 != 0); + use ab_glyph::{Font as _, ScaleFont}; - let glyph = glyph.scaled(Scale::uniform(scale_in_pixels)); - let glyph = glyph.positioned(point(0.0, 0.0)); + let glyph = + glyph_id.with_scale_and_position(scale_in_pixels, ab_glyph::Point { x: 0.0, y: 0.0 }); - let uv_rect = if let Some(bb) = glyph.pixel_bounding_box() { + let uv_rect = font.outline_glyph(glyph).and_then(|glyph| { + let bb = glyph.px_bounds(); let glyph_width = bb.width() as usize; let glyph_height = bb.height() as usize; - if glyph_width == 0 || glyph_height == 0 { None } else { @@ -658,15 +658,13 @@ fn allocate_glyph( ), }) } - } else { - // No bounding box. Maybe a space? - None - }; + }); - let advance_width_in_points = glyph.unpositioned().h_metrics().advance_width / pixels_per_point; + let advance_width_in_points = + font.as_scaled(scale_in_pixels).h_advance(glyph_id) / pixels_per_point; GlyphInfo { - id: glyph.id(), + id: glyph_id, advance_width: advance_width_in_points, uv_rect, } diff --git a/epaint/src/text/fonts.rs b/epaint/src/text/fonts.rs index c2e9068b..3afaae0b 100644 --- a/epaint/src/text/fonts.rs +++ b/epaint/src/text/fonts.rs @@ -61,12 +61,12 @@ pub enum FontFamily { /// The data of a `.ttf` or `.otf` file. pub type FontData = std::borrow::Cow<'static, [u8]>; -fn rusttype_font_from_font_data(name: &str, data: &FontData) -> rusttype::Font<'static> { +fn ab_glyph_font_from_font_data(name: &str, data: &FontData) -> ab_glyph::FontArc { match data { - std::borrow::Cow::Borrowed(bytes) => rusttype::Font::try_from_bytes(bytes), - std::borrow::Cow::Owned(bytes) => rusttype::Font::try_from_vec(bytes.clone()), + std::borrow::Cow::Borrowed(bytes) => ab_glyph::FontArc::try_from_slice(bytes), + std::borrow::Cow::Owned(bytes) => ab_glyph::FontArc::try_from_vec(bytes.clone()), } - .unwrap_or_else(|| panic!("Error parsing {:?} TTF/OTF font file", name)) + .unwrap_or_else(|err| panic!("Error parsing {:?} TTF/OTF font file: {}", name, err)) } /// Describes the font data and the sizes to use. @@ -484,7 +484,7 @@ impl GalleyCache { struct FontImplCache { atlas: Arc>, pixels_per_point: f32, - rusttype_fonts: BTreeMap>>, + ab_glyph_fonts: BTreeMap, /// Map font names and size to the cached `FontImpl`. /// Can't have f32 in a HashMap or BTreeMap, so let's do a linear search @@ -497,27 +497,22 @@ impl FontImplCache { pixels_per_point: f32, definitions: &super::FontDefinitions, ) -> Self { - let rusttype_fonts = definitions + let ab_glyph_fonts = definitions .font_data .iter() - .map(|(name, font_data)| { - ( - name.clone(), - Arc::new(rusttype_font_from_font_data(name, font_data)), - ) - }) + .map(|(name, font_data)| (name.clone(), ab_glyph_font_from_font_data(name, font_data))) .collect(); Self { atlas, pixels_per_point, - rusttype_fonts, + ab_glyph_fonts, cache: Default::default(), } } - pub fn rusttype_font(&self, font_name: &str) -> Arc> { - self.rusttype_fonts + pub fn ab_glyph_font(&self, font_name: &str) -> ab_glyph::FontArc { + self.ab_glyph_fonts .get(font_name) .unwrap_or_else(|| panic!("No font data found for {:?}", font_name)) .clone() @@ -546,7 +541,7 @@ impl FontImplCache { let font_impl = Arc::new(FontImpl::new( self.atlas.clone(), self.pixels_per_point, - self.rusttype_font(font_name), + self.ab_glyph_font(font_name), scale_in_points, y_offset, ));