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"]
[dependencies]
app_units = "0.5"
app_units = "0.6"
base64 = "0.6"
bincode = "0.8"
env_logger = "0.4"

View File

@ -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<LruCache<MeshLibraryCacheKey, PartitionResponder>> = {
Mutex::new(LruCache::new(MESH_LIBRARY_CACHE_SIZE))
@ -261,6 +264,15 @@ struct PartitionSvgPathCommand {
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 {
encoded_data: Arc<Vec<u8>>,
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,
font_index: u32,
otf_data: Arc<Vec<u8>>,
font_instance: &FontInstance,
font_instance: &FontInstance<FontKey>,
glyph_key: &GlyphKey)
-> Result<GlyphImage, FontError> {
let mut font_context =

View File

@ -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"

View File

@ -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<FontKey, CGFont>,
core_text_fonts: BTreeMap<FontInstance, CTFont>,
pub struct FontContext<FK> where FK: Clone + Hash + Eq + Ord {
core_graphics_fonts: BTreeMap<FK, CGFont>,
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.
pub fn new() -> Result<FontContext, ()> {
pub fn new() -> Result<Self, ()> {
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<Vec<u8>>, _: u32)
pub fn add_font_from_memory(&mut self, font_key: &FK, bytes: Arc<Vec<u8>>, _: 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<CTFont, ()> {
match self.core_text_fonts.entry(*font_instance) {
fn ensure_core_text_font(&mut self, font_instance: &FontInstance<FK>) -> Result<CTFont, ()> {
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<FK>,
glyph_key: &GlyphKey,
exact: bool)
-> Result<GlyphDimensions, ()> {
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<FK>, glyph_key: &GlyphKey)
-> Result<GlyphOutline, ()> {
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<FK>,
glyph_key: &GlyphKey,
exact: bool)
-> 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, ()> {
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 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<FK> 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<FK> FontInstance<FK> 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<FK> {
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<f32> for SubpixelOffset {

View File

@ -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)]

View File

@ -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;
}

View File

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