Abstract away `FontKey` so WebRender can more easily use this; switch

from angle measurement to scale-dependent hull height
This commit is contained in:
Patrick Walton 2018-03-05 11:27:18 -08:00
parent 45a812d30f
commit 5d3c1f6d59
8 changed files with 71 additions and 69 deletions

View File

@ -8,7 +8,7 @@ default = []
reftests = ["rsvg", "cairo-rs", "pathfinder_font_renderer/freetype"] reftests = ["rsvg", "cairo-rs", "pathfinder_font_renderer/freetype"]
[dependencies] [dependencies]
app_units = "0.5" app_units = "0.6"
base64 = "0.6" base64 = "0.6"
bincode = "0.8" bincode = "0.8"
env_logger = "0.4" env_logger = "0.4"

View File

@ -43,7 +43,7 @@ use lru_cache::LruCache;
use lyon_path::PathEvent; use lyon_path::PathEvent;
use lyon_path::builder::{FlatPathBuilder, PathBuilder}; use lyon_path::builder::{FlatPathBuilder, PathBuilder};
use lyon_path::iterator::PathIter; 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_font_renderer::{GlyphKey, SubpixelOffset};
use pathfinder_partitioner::FillRule; use pathfinder_partitioner::FillRule;
use pathfinder_partitioner::mesh_library::MeshLibrary; use pathfinder_partitioner::mesh_library::MeshLibrary;
@ -57,6 +57,7 @@ use rocket_contrib::json::Json;
use std::fs::File; use std::fs::File;
use std::io::{self, Cursor, Read}; use std::io::{self, Cursor, Read};
use std::path::{self, PathBuf}; use std::path::{self, PathBuf};
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use std::u32; use std::u32;
@ -75,6 +76,8 @@ const SUGGESTED_JSON_SIZE_LIMIT: u64 = 32 * 1024 * 1024;
const MESH_LIBRARY_CACHE_SIZE: usize = 16; const MESH_LIBRARY_CACHE_SIZE: usize = 16;
static NEXT_FONT_KEY: AtomicUsize = ATOMIC_USIZE_INIT;
lazy_static! { lazy_static! {
static ref MESH_LIBRARY_CACHE: Mutex<LruCache<MeshLibraryCacheKey, PartitionResponder>> = { static ref MESH_LIBRARY_CACHE: Mutex<LruCache<MeshLibraryCacheKey, PartitionResponder>> = {
Mutex::new(LruCache::new(MESH_LIBRARY_CACHE_SIZE)) Mutex::new(LruCache::new(MESH_LIBRARY_CACHE_SIZE))
@ -261,6 +264,15 @@ struct PartitionSvgPathCommand {
values: Vec<f64>, values: Vec<f64>,
} }
#[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 { struct PathPartitioningResult {
encoded_data: Arc<Vec<u8>>, encoded_data: Arc<Vec<u8>>,
time: Duration, time: Duration,
@ -387,7 +399,7 @@ fn svg_data_from_request(builtin_svg_name: &str) -> Result<Arc<Vec<u8>>, SvgErro
fn rasterize_glyph_with_core_graphics(font_key: &FontKey, fn rasterize_glyph_with_core_graphics(font_key: &FontKey,
font_index: u32, font_index: u32,
otf_data: Arc<Vec<u8>>, otf_data: Arc<Vec<u8>>,
font_instance: &FontInstance, font_instance: &FontInstance<FontKey>,
glyph_key: &GlyphKey) glyph_key: &GlyphKey)
-> Result<GlyphImage, FontError> { -> Result<GlyphImage, FontError> {
let mut font_context = let mut font_context =

View File

@ -8,7 +8,7 @@ default = []
freetype = ["freetype-sys"] freetype = ["freetype-sys"]
[dependencies] [dependencies]
app_units = "0.5" app_units = "0.6"
euclid = "0.16" euclid = "0.16"
libc = "0.2" libc = "0.2"
log = "0.3" log = "0.3"
@ -25,12 +25,10 @@ optional = true
freetype-sys = "0.6" freetype-sys = "0.6"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
core-graphics = "0.13"
[target.'cfg(target_os = "macos")'.dependencies.core-graphics]
git = "https://github.com/pcwalton/rust-core-graphics.git"
[target.'cfg(target_os = "macos")'.dependencies.core-text] [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] [target.'cfg(target_os = "windows")'.dependencies]
dwrite-sys = "0.2" dwrite-sys = "0.2"

View File

@ -24,10 +24,11 @@ use euclid::{Point2D, Rect, Size2D, Vector2D};
use lyon_path::PathEvent; use lyon_path::PathEvent;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::collections::btree_map::Entry; use std::collections::btree_map::Entry;
use std::hash::Hash;
use std::iter::Cloned; use std::iter::Cloned;
use std::slice::Iter; use std::slice::Iter;
use std::sync::Arc; use std::sync::Arc;
use {FontInstance, FontKey, GlyphDimensions, GlyphImage, GlyphKey}; use {FontInstance, GlyphDimensions, GlyphImage, GlyphKey};
const CG_ZERO_RECT: CGRect = CGRect { const CG_ZERO_RECT: CGRect = CGRect {
origin: CG_ZERO_POINT, origin: CG_ZERO_POINT,
@ -44,21 +45,39 @@ const CG_ZERO_RECT: CGRect = CGRect {
// direction. // direction.
const FONT_DILATION_AMOUNT: f32 = 0.02; 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. /// An object that loads and renders fonts using macOS Core Graphics/Quartz.
pub struct FontContext { pub struct FontContext<FK> where FK: Clone + Hash + Eq + Ord {
core_graphics_fonts: BTreeMap<FontKey, CGFont>, core_graphics_fonts: BTreeMap<FK, CGFont>,
core_text_fonts: BTreeMap<FontInstance, CTFont>, core_text_fonts: BTreeMap<FontInstance<FK>, CTFont>,
} }
impl FontContext { // Core Text is thread-safe.
unsafe impl<FK> Send for FontContext<FK> where FK: Clone + Hash + Eq + Ord {}
impl<FK> FontContext<FK> where FK: Clone + Hash + Eq + Ord {
/// Creates a new font context instance. /// Creates a new font context instance.
pub fn new() -> Result<FontContext, ()> { pub fn new() -> Result<Self, ()> {
Ok(FontContext { Ok(FontContext {
core_graphics_fonts: BTreeMap::new(), core_graphics_fonts: BTreeMap::new(),
core_text_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. /// 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 /// `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 /// `font_index` is the index of the font within the collection, if `bytes` refers to a
/// collection (`.ttc`). /// collection (`.ttc`).
pub fn add_font_from_memory(&mut self, font_key: &FontKey, bytes: Arc<Vec<u8>>, _: u32) pub fn add_font_from_memory(&mut self, font_key: &FK, bytes: Arc<Vec<u8>>, _: u32)
-> Result<(), ()> { -> Result<(), ()> {
match self.core_graphics_fonts.entry(*font_key) { match self.core_graphics_fonts.entry((*font_key).clone()) {
Entry::Occupied(_) => Ok(()), Entry::Occupied(_) => Ok(()),
Entry::Vacant(entry) => { Entry::Vacant(entry) => {
let data_provider = CGDataProvider::from_buffer(bytes); let data_provider = CGDataProvider::from_buffer(bytes);
@ -84,7 +103,7 @@ impl FontContext {
/// Unloads the font with the given font key from memory. /// Unloads the font with the given font key from memory.
/// ///
/// If the font isn't loaded, does nothing. /// 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); self.core_graphics_fonts.remove(font_key);
let core_text_font_keys: Vec<_> = self.core_text_fonts 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<CTFont, ()> { fn ensure_core_text_font(&mut self, font_instance: &FontInstance<FK>) -> Result<CTFont, ()> {
match self.core_text_fonts.entry(*font_instance) { match self.core_text_fonts.entry((*font_instance).clone()) {
Entry::Occupied(entry) => Ok((*entry.get()).clone()), Entry::Occupied(entry) => Ok((*entry.get()).clone()),
Entry::Vacant(entry) => { Entry::Vacant(entry) => {
let core_graphics_font = match self.core_graphics_fonts 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 /// libraries (including Pathfinder) apply modifications to the outlines: for example, to
/// dilate them for easier reading. To retrieve extents that account for these modifications, /// dilate them for easier reading. To retrieve extents that account for these modifications,
/// set `exact` to false. /// 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<FK>,
glyph_key: &GlyphKey,
exact: bool)
-> Result<GlyphDimensions, ()> { -> Result<GlyphDimensions, ()> {
let core_graphics_font = match self.core_graphics_fonts.get(&font_instance.font_key) { let core_graphics_font = match self.core_graphics_fonts.get(&font_instance.font_key) {
None => return Err(()), None => return Err(()),
@ -174,7 +196,7 @@ impl FontContext {
} }
/// Returns a list of path commands that represent the given glyph in the given font. /// 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<FK>, glyph_key: &GlyphKey)
-> Result<GlyphOutline, ()> { -> Result<GlyphOutline, ()> {
let core_text_font = try!(self.ensure_core_text_font(font_instance)); 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, 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 /// 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`. /// glyph outlines, to ensure the entire outline fits it is best to pass false for `exact`.
pub fn rasterize_glyph_with_native_rasterizer(&self, pub fn rasterize_glyph_with_native_rasterizer(&self,
font_instance: &FontInstance, font_instance: &FontInstance<FK>,
glyph_key: &GlyphKey, glyph_key: &GlyphKey,
exact: bool) exact: bool)
-> Result<GlyphImage, ()> { -> Result<GlyphImage, ()> {
@ -305,7 +327,7 @@ impl FontContext {
} }
} }
impl FontInstance { impl<FK> FontInstance<FK> where FK: Clone {
fn instantiate(&self, core_graphics_font: &CGFont) -> Result<CTFont, ()> { fn instantiate(&self, core_graphics_font: &CGFont) -> Result<CTFont, ()> {
Ok(core_text::font::new_from_CGFont(core_graphics_font, self.size.to_f64_px())) Ok(core_text::font::new_from_CGFont(core_graphics_font, self.size.to_f64_px()))
} }

View File

@ -55,13 +55,12 @@ extern crate winapi;
use app_units::Au; use app_units::Au;
use euclid::{Point2D, Size2D}; use euclid::{Point2D, Size2D};
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
#[cfg(all(target_os = "macos", not(feature = "freetype")))] #[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")))] #[cfg(all(target_os = "windows", not(feature = "freetype")))]
pub use directwrite::FontContext; pub use directwrite::FontContext;
#[cfg(any(target_os = "linux", feature = "freetype"))] #[cfg(any(target_os = "linux", feature = "freetype"))]
@ -80,44 +79,11 @@ mod freetype;
/// Right now, each glyph is snapped to the nearest quarter-pixel. /// Right now, each glyph is snapped to the nearest quarter-pixel.
pub const SUBPIXEL_GRANULARITY: u8 = 4; 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. /// A font at one specific size.
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
pub struct FontInstance { pub struct FontInstance<FK> where FK: Clone {
/// The opaque font key that this font instance represents. /// The opaque font key that this font instance represents.
pub font_key: FontKey, pub font_key: FK,
/// The size of the font. /// The size of the font.
/// ///
@ -125,19 +91,19 @@ pub struct FontInstance {
pub size: Au, pub size: Au,
} }
impl FontInstance { impl<FK> FontInstance<FK> where FK: Clone {
/// Creates a new instance of a font at the given size. /// Creates a new instance of a font at the given size.
#[inline] #[inline]
pub fn new(font_key: &FontKey, size: Au) -> FontInstance { pub fn new(font_key: &FK, size: Au) -> FontInstance<FK> {
FontInstance { FontInstance {
font_key: *font_key, font_key: (*font_key).clone(),
size: size, size: size,
} }
} }
} }
/// A subpixel offset, from 0 to `SUBPIXEL_GRANULARITY`. /// 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); pub struct SubpixelOffset(pub u8);
impl Into<f32> for SubpixelOffset { impl Into<f32> for SubpixelOffset {

View File

@ -403,6 +403,11 @@ impl MeshLibrary {
b_boxes: self.b_boxes.len() as u32, 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)] #[derive(Debug, Clone)]

View File

@ -80,10 +80,9 @@ void main() {
// Compute area of convex hull (w). Change from curve to line if appropriate. // Compute area of convex hull (w). Change from curve to line if appropriate.
float w = det2(mat2(v01, v02)); float w = det2(mat2(v01, v02));
float sqLen01 = dot(v01, v01), sqLen02 = dot(v02, v02), sqLen21 = dot(v21, v21); float sqLen01 = dot(v01, v01), sqLen02 = dot(v02, v02), sqLen21 = dot(v21, v21);
float minCtrlSqLen = dot(v02, v02) * 0.0001; float hullHeight = abs(w * inversesqrt(sqLen02));
float cosTheta = dot(v01, v21); float minCtrlSqLen = sqLen02 * 0.01;
if (sqLen01 < minCtrlSqLen || sqLen21 < minCtrlSqLen || if (sqLen01 < minCtrlSqLen || sqLen21 < minCtrlSqLen || hullHeight < 0.0001) {
cosTheta * cosTheta >= 0.95 * sqLen01 * sqLen21) {
w = 0.0; w = 0.0;
v01 = vec2(0.5, abs(v02.y) >= 0.01 ? 0.0 : 0.5) * v02.xx; v01 = vec2(0.5, abs(v02.y) >= 0.01 ? 0.0 : 0.5) * v02.xx;
} }

View File

@ -4,7 +4,7 @@ version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"] authors = ["Patrick Walton <pcwalton@mimiga.net>"]
[dependencies] [dependencies]
app_units = "0.5" app_units = "0.6"
clap = "2.27" clap = "2.27"
freetype-sys = "0.6" freetype-sys = "0.6"
lyon_geom = "0.9" lyon_geom = "0.9"