From 5d3c1f6d596a3b82b55c59c3a687d83d757950ef Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 5 Mar 2018 11:27:18 -0800 Subject: [PATCH] Abstract away `FontKey` so WebRender can more easily use this; switch from angle measurement to scale-dependent hull height --- demo/server/Cargo.toml | 2 +- demo/server/src/main.rs | 16 +++++++-- font-renderer/Cargo.toml | 8 ++--- font-renderer/src/core_graphics.rs | 52 +++++++++++++++++++++--------- font-renderer/src/lib.rs | 48 ++++----------------------- partitioner/src/mesh_library.rs | 5 +++ shaders/gles2/stencil-aaa.vs.glsl | 7 ++-- utils/frontend/Cargo.toml | 2 +- 8 files changed, 71 insertions(+), 69 deletions(-) diff --git a/demo/server/Cargo.toml b/demo/server/Cargo.toml index 8066e20b..522e1d0e 100644 --- a/demo/server/Cargo.toml +++ b/demo/server/Cargo.toml @@ -8,7 +8,7 @@ default = [] reftests = ["rsvg", "cairo-rs", "pathfinder_font_renderer/freetype"] [dependencies] -app_units = "0.5" +app_units = "0.6" base64 = "0.6" bincode = "0.8" env_logger = "0.4" diff --git a/demo/server/src/main.rs b/demo/server/src/main.rs index ea22b679..f3544eba 100644 --- a/demo/server/src/main.rs +++ b/demo/server/src/main.rs @@ -43,7 +43,7 @@ use lru_cache::LruCache; use lyon_path::PathEvent; use lyon_path::builder::{FlatPathBuilder, PathBuilder}; use lyon_path::iterator::PathIter; -use pathfinder_font_renderer::{FontContext, FontInstance, FontKey, GlyphImage}; +use pathfinder_font_renderer::{FontContext, FontInstance, GlyphImage}; use pathfinder_font_renderer::{GlyphKey, SubpixelOffset}; use pathfinder_partitioner::FillRule; use pathfinder_partitioner::mesh_library::MeshLibrary; @@ -57,6 +57,7 @@ use rocket_contrib::json::Json; use std::fs::File; use std::io::{self, Cursor, Read}; use std::path::{self, PathBuf}; +use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; use std::u32; @@ -75,6 +76,8 @@ const SUGGESTED_JSON_SIZE_LIMIT: u64 = 32 * 1024 * 1024; const MESH_LIBRARY_CACHE_SIZE: usize = 16; +static NEXT_FONT_KEY: AtomicUsize = ATOMIC_USIZE_INIT; + lazy_static! { static ref MESH_LIBRARY_CACHE: Mutex> = { Mutex::new(LruCache::new(MESH_LIBRARY_CACHE_SIZE)) @@ -261,6 +264,15 @@ struct PartitionSvgPathCommand { values: Vec, } +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)] +struct FontKey(usize); + +impl FontKey { + fn new() -> FontKey { + FontKey(NEXT_FONT_KEY.fetch_add(1, Ordering::SeqCst)) + } +} + struct PathPartitioningResult { encoded_data: Arc>, time: Duration, @@ -387,7 +399,7 @@ fn svg_data_from_request(builtin_svg_name: &str) -> Result>, SvgErro fn rasterize_glyph_with_core_graphics(font_key: &FontKey, font_index: u32, otf_data: Arc>, - font_instance: &FontInstance, + font_instance: &FontInstance, glyph_key: &GlyphKey) -> Result { let mut font_context = diff --git a/font-renderer/Cargo.toml b/font-renderer/Cargo.toml index 6e663933..7dc5518d 100644 --- a/font-renderer/Cargo.toml +++ b/font-renderer/Cargo.toml @@ -8,7 +8,7 @@ default = [] freetype = ["freetype-sys"] [dependencies] -app_units = "0.5" +app_units = "0.6" euclid = "0.16" libc = "0.2" log = "0.3" @@ -25,12 +25,10 @@ optional = true freetype-sys = "0.6" [target.'cfg(target_os = "macos")'.dependencies] - -[target.'cfg(target_os = "macos")'.dependencies.core-graphics] -git = "https://github.com/pcwalton/rust-core-graphics.git" +core-graphics = "0.13" [target.'cfg(target_os = "macos")'.dependencies.core-text] -git = "https://github.com/pcwalton/rust-core-text.git" +git = "https://github.com/servo/core-text-rs.git" [target.'cfg(target_os = "windows")'.dependencies] dwrite-sys = "0.2" diff --git a/font-renderer/src/core_graphics.rs b/font-renderer/src/core_graphics.rs index 7ebcb689..09afb67d 100644 --- a/font-renderer/src/core_graphics.rs +++ b/font-renderer/src/core_graphics.rs @@ -24,10 +24,11 @@ use euclid::{Point2D, Rect, Size2D, Vector2D}; use lyon_path::PathEvent; use std::collections::BTreeMap; use std::collections::btree_map::Entry; +use std::hash::Hash; use std::iter::Cloned; use std::slice::Iter; use std::sync::Arc; -use {FontInstance, FontKey, GlyphDimensions, GlyphImage, GlyphKey}; +use {FontInstance, GlyphDimensions, GlyphImage, GlyphKey}; const CG_ZERO_RECT: CGRect = CGRect { origin: CG_ZERO_POINT, @@ -44,21 +45,39 @@ const CG_ZERO_RECT: CGRect = CGRect { // direction. const FONT_DILATION_AMOUNT: f32 = 0.02; +#[cfg(target_os = "macos")] +#[derive(Clone)] +pub struct NativeFontHandle(pub CGFont); + /// An object that loads and renders fonts using macOS Core Graphics/Quartz. -pub struct FontContext { - core_graphics_fonts: BTreeMap, - core_text_fonts: BTreeMap, +pub struct FontContext where FK: Clone + Hash + Eq + Ord { + core_graphics_fonts: BTreeMap, + core_text_fonts: BTreeMap, CTFont>, } -impl FontContext { +// Core Text is thread-safe. +unsafe impl Send for FontContext where FK: Clone + Hash + Eq + Ord {} + +impl FontContext where FK: Clone + Hash + Eq + Ord { /// Creates a new font context instance. - pub fn new() -> Result { + pub fn new() -> Result { Ok(FontContext { core_graphics_fonts: BTreeMap::new(), core_text_fonts: BTreeMap::new(), }) } + /// Loads an OpenType font from a Quartz `CGFont` handle. + pub fn add_native_font(&mut self, font_key: &FK, handle: CGFont) -> Result<(), ()> { + match self.core_graphics_fonts.entry((*font_key).clone()) { + Entry::Occupied(_) => Ok(()), + Entry::Vacant(entry) => { + entry.insert(handle); + Ok(()) + } + } + } + /// Loads an OpenType font from memory. /// /// `font_key` is a handle that is used to refer to the font later. If this context has already @@ -68,9 +87,9 @@ impl FontContext { /// /// `font_index` is the index of the font within the collection, if `bytes` refers to a /// collection (`.ttc`). - pub fn add_font_from_memory(&mut self, font_key: &FontKey, bytes: Arc>, _: u32) + pub fn add_font_from_memory(&mut self, font_key: &FK, bytes: Arc>, _: u32) -> Result<(), ()> { - match self.core_graphics_fonts.entry(*font_key) { + match self.core_graphics_fonts.entry((*font_key).clone()) { Entry::Occupied(_) => Ok(()), Entry::Vacant(entry) => { let data_provider = CGDataProvider::from_buffer(bytes); @@ -84,7 +103,7 @@ impl FontContext { /// Unloads the font with the given font key from memory. /// /// If the font isn't loaded, does nothing. - pub fn delete_font(&mut self, font_key: &FontKey) { + pub fn delete_font(&mut self, font_key: &FK) { self.core_graphics_fonts.remove(font_key); let core_text_font_keys: Vec<_> = self.core_text_fonts @@ -97,8 +116,8 @@ impl FontContext { } } - fn ensure_core_text_font(&mut self, font_instance: &FontInstance) -> Result { - match self.core_text_fonts.entry(*font_instance) { + fn ensure_core_text_font(&mut self, font_instance: &FontInstance) -> Result { + match self.core_text_fonts.entry((*font_instance).clone()) { Entry::Occupied(entry) => Ok((*entry.get()).clone()), Entry::Vacant(entry) => { let core_graphics_font = match self.core_graphics_fonts @@ -121,7 +140,10 @@ impl FontContext { /// libraries (including Pathfinder) apply modifications to the outlines: for example, to /// dilate them for easier reading. To retrieve extents that account for these modifications, /// set `exact` to false. - pub fn glyph_dimensions(&self, font_instance: &FontInstance, glyph_key: &GlyphKey, exact: bool) + pub fn glyph_dimensions(&self, + font_instance: &FontInstance, + glyph_key: &GlyphKey, + exact: bool) -> Result { let core_graphics_font = match self.core_graphics_fonts.get(&font_instance.font_key) { None => return Err(()), @@ -174,7 +196,7 @@ impl FontContext { } /// Returns a list of path commands that represent the given glyph in the given font. - pub fn glyph_outline(&mut self, font_instance: &FontInstance, glyph_key: &GlyphKey) + pub fn glyph_outline(&mut self, font_instance: &FontInstance, glyph_key: &GlyphKey) -> Result { let core_text_font = try!(self.ensure_core_text_font(font_instance)); let path = try!(core_text_font.create_path_for_glyph(glyph_key.glyph_index as CGGlyph, @@ -220,7 +242,7 @@ impl FontContext { /// designer. Because some font libraries, such as Core Graphics, perform modifications to the /// glyph outlines, to ensure the entire outline fits it is best to pass false for `exact`. pub fn rasterize_glyph_with_native_rasterizer(&self, - font_instance: &FontInstance, + font_instance: &FontInstance, glyph_key: &GlyphKey, exact: bool) -> Result { @@ -305,7 +327,7 @@ impl FontContext { } } -impl FontInstance { +impl FontInstance where FK: Clone { fn instantiate(&self, core_graphics_font: &CGFont) -> Result { Ok(core_text::font::new_from_CGFont(core_graphics_font, self.size.to_f64_px())) } diff --git a/font-renderer/src/lib.rs b/font-renderer/src/lib.rs index 3ea8929d..51c18903 100644 --- a/font-renderer/src/lib.rs +++ b/font-renderer/src/lib.rs @@ -55,13 +55,12 @@ extern crate winapi; use app_units::Au; use euclid::{Point2D, Size2D}; -use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering}; #[cfg(test)] mod tests; #[cfg(all(target_os = "macos", not(feature = "freetype")))] -pub use core_graphics::FontContext; +pub use core_graphics::{FontContext, GlyphOutline}; #[cfg(all(target_os = "windows", not(feature = "freetype")))] pub use directwrite::FontContext; #[cfg(any(target_os = "linux", feature = "freetype"))] @@ -80,44 +79,11 @@ mod freetype; /// Right now, each glyph is snapped to the nearest quarter-pixel. pub const SUBPIXEL_GRANULARITY: u8 = 4; -/// An opaque handle that represents a loaded font. -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)] -pub struct FontKey { - id: usize, -} - -impl FontKey { - /// Constructs a new opaque font key distinct from all others. - pub fn new() -> FontKey { - static NEXT_FONT_KEY_ID: AtomicUsize = ATOMIC_USIZE_INIT; - FontKey { - id: NEXT_FONT_KEY_ID.fetch_add(1, Ordering::Relaxed), - } - } -} - -/// An opaque font that represents a loaded font *at one specific size*. -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)] -pub struct FontInstanceKey { - id: usize, -} - -impl FontInstanceKey { - /// Creates a new opaque font instance key distinct from all others. - #[inline] - pub fn new() -> FontInstanceKey { - static NEXT_FONT_INSTANCE_KEY_ID: AtomicUsize = ATOMIC_USIZE_INIT; - FontInstanceKey { - id: NEXT_FONT_INSTANCE_KEY_ID.fetch_add(1, Ordering::Relaxed), - } - } -} - /// A font at one specific size. #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)] -pub struct FontInstance { +pub struct FontInstance where FK: Clone { /// The opaque font key that this font instance represents. - pub font_key: FontKey, + pub font_key: FK, /// The size of the font. /// @@ -125,19 +91,19 @@ pub struct FontInstance { pub size: Au, } -impl FontInstance { +impl FontInstance where FK: Clone { /// Creates a new instance of a font at the given size. #[inline] - pub fn new(font_key: &FontKey, size: Au) -> FontInstance { + pub fn new(font_key: &FK, size: Au) -> FontInstance { FontInstance { - font_key: *font_key, + font_key: (*font_key).clone(), size: size, } } } /// A subpixel offset, from 0 to `SUBPIXEL_GRANULARITY`. -#[derive(Clone, Copy, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)] pub struct SubpixelOffset(pub u8); impl Into for SubpixelOffset { diff --git a/partitioner/src/mesh_library.rs b/partitioner/src/mesh_library.rs index 7e3f3192..162ae63b 100644 --- a/partitioner/src/mesh_library.rs +++ b/partitioner/src/mesh_library.rs @@ -403,6 +403,11 @@ impl MeshLibrary { b_boxes: self.b_boxes.len() as u32, } } + + #[inline] + pub fn next_path_id(&self) -> u16 { + (self.path_ranges.len() + 1) as u16 + } } #[derive(Debug, Clone)] diff --git a/shaders/gles2/stencil-aaa.vs.glsl b/shaders/gles2/stencil-aaa.vs.glsl index aef0514d..74f458cc 100644 --- a/shaders/gles2/stencil-aaa.vs.glsl +++ b/shaders/gles2/stencil-aaa.vs.glsl @@ -80,10 +80,9 @@ void main() { // Compute area of convex hull (w). Change from curve to line if appropriate. float w = det2(mat2(v01, v02)); float sqLen01 = dot(v01, v01), sqLen02 = dot(v02, v02), sqLen21 = dot(v21, v21); - float minCtrlSqLen = dot(v02, v02) * 0.0001; - float cosTheta = dot(v01, v21); - if (sqLen01 < minCtrlSqLen || sqLen21 < minCtrlSqLen || - cosTheta * cosTheta >= 0.95 * sqLen01 * sqLen21) { + float hullHeight = abs(w * inversesqrt(sqLen02)); + float minCtrlSqLen = sqLen02 * 0.01; + if (sqLen01 < minCtrlSqLen || sqLen21 < minCtrlSqLen || hullHeight < 0.0001) { w = 0.0; v01 = vec2(0.5, abs(v02.y) >= 0.01 ? 0.0 : 0.5) * v02.xx; } diff --git a/utils/frontend/Cargo.toml b/utils/frontend/Cargo.toml index f75e04ff..7da2fb9d 100644 --- a/utils/frontend/Cargo.toml +++ b/utils/frontend/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Patrick Walton "] [dependencies] -app_units = "0.5" +app_units = "0.6" clap = "2.27" freetype-sys = "0.6" lyon_geom = "0.9"