font widths are WAY better now

macos-click-through
Keith Simmons 5 years ago
parent ab6c1d5700
commit 005797b276

1544
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -9,7 +9,7 @@ euclid = "0.20.7"
font-kit = "0.4.0" font-kit = "0.4.0"
skribo = { git = "https://github.com/linebender/skribo" } skribo = { git = "https://github.com/linebender/skribo" }
lru = "0.4.3" lru = "0.4.3"
skulpin = "0.4" skulpin = { path = "../skulpin" }
derive-new = "0.5" derive-new = "0.5"
env_logger = "0.7.1" env_logger = "0.7.1"
neovim-lib = { git = "https://github.com/daa84/neovim-lib", version = "0.6" } neovim-lib = { git = "https://github.com/daa84/neovim-lib", version = "0.6" }

@ -1,3 +1,6 @@
use std::collections::HashMap;
use std::rc::Rc;
use lru::LruCache; use lru::LruCache;
use skulpin::skia_safe::{Shaper, TextBlob, Font, Point, TextBlobBuilder}; use skulpin::skia_safe::{Shaper, TextBlob, Font, Point, TextBlobBuilder};
use font_kit::source::SystemSource; use font_kit::source::SystemSource;
@ -6,9 +9,14 @@ use skribo::{
TextStyle TextStyle
}; };
use super::fonts::FontLookup;
const standard_character_string: &'static str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
#[derive(new, Clone, Hash, PartialEq, Eq)] #[derive(new, Clone, Hash, PartialEq, Eq)]
struct FontKey { struct FontKey {
pub name: String, pub name: String,
pub base_size: String, // hack because comparison of floats doesn't work
pub scale: u16, pub scale: u16,
pub bold: bool, pub bold: bool,
pub italic: bool pub italic: bool
@ -33,7 +41,7 @@ impl CachingShaper {
} }
} }
fn get_font(&self, font_key: &FontKey) -> &FontRef { fn get_font(&mut self, font_key: &FontKey) -> &FontRef {
if !self.font_cache.contains(font_key) { if !self.font_cache.contains(font_key) {
let source = SystemSource::new(); let source = SystemSource::new();
let font_name = font_key.name.clone(); let font_name = font_key.name.clone();
@ -43,51 +51,43 @@ impl CachingShaper {
.fonts()[0] .fonts()[0]
.load() .load()
.unwrap(); .unwrap();
self.font_cache.put(key.clone(), FontRef::new(font)); self.font_cache.put(font_key.clone(), FontRef::new(font));
} }
self.font_cache.get(&key).unwrap() self.font_cache.get(font_key).unwrap()
} }
pub fn shape(&self, text: &str, font_name: &str, scale: u16, bold: bool, italic: bool, font: &Font) -> TextBlob { pub fn shape(&mut self, text: &str, font_name: &str, base_size: f32, scale: u16, bold: bool, italic: bool, font: &Font) -> TextBlob {
let font_key = FontKey::new(font_name.to_string(), scale, bold, italic); let font_key = FontKey::new(font_name.to_string(), base_size.to_string(), scale, bold, italic);
let font_ref = self.get_font(&font_key); let font_ref = self.get_font(&font_key);
let style = TextStyle { size: font_size }; let style = TextStyle { size: base_size * scale as f32 };
let layout = layout_run(&style, &font_ref, standard_character_string); let layout = layout_run(&style, &font_ref, text);
let blob_builder = TextBlobBuilder::new();
unsafe {
let count = layout.glyphs.count();
let buffer = blob_builder
.native_mut()
.allocRunPosH(font.native(), count.try_into().unwrap(), 0, None);
let mut glyphs = slice::from_raw_parts_mut((*buffer).glyphs, count);
for (glyph_id, i) in layout.glyphs.iter().map(|glyph| glyph.glyph_id as u16).enumerate() {
glyphs[i] = glyph_id;
}
let mut positions = slice::from_raw_parts_mut((*buffer).pos, count);
for (offset, i) in layout.glyphs.iter().map(|glyph| glyph.offset.x as f32).enumerate() {
positions[i] = offset;
}
}
blob_builder.make() let mut blob_builder = TextBlobBuilder::new();
// TextBlob::from_pos_text_h(text.as_bytes(), layout.glyphs.iter().
// let (mut glyphs, mut points) = blob_builder.alloc_run_pos(
// // let glyph_offsets: Vec<f32> = layout.glyphs.iter().map(|glyph| glyph.offset.x).collect(); let count = layout.glyphs.len();
// // let glyph_advances: Vec<f32> = glyph_offsets.windows(2).map(|pair| pair[1] - pair[0]).collect(); let metrics = font_ref.font.metrics();
let ascent = metrics.ascent * base_size / metrics.units_per_em as f32;
let (glyphs, positions) = blob_builder.alloc_run_pos_h(font, count, ascent, None);
for (i, glyph_id) in layout.glyphs.iter().map(|glyph| glyph.glyph_id as u16).enumerate() {
glyphs[i] = glyph_id;
}
for (i, offset) in layout.glyphs.iter().map(|glyph| glyph.offset.x as f32).enumerate() {
positions[i] = offset;
}
// let (blob, _) = self.shaper.shape_text_blob(text, font, true, 1000000.0, Point::default()).unwrap(); blob_builder.make().unwrap()
// blob
} }
pub fn shape_cached(&mut self, text: &str, font_name: &str, scale: u16, bold: bool, italic: bool, font: &Font) -> &TextBlob { pub fn shape_cached(&mut self, text: &str, font_name: &str, base_size: f32, scale: u16, bold: bool, italic: bool, font: &Font) -> &TextBlob {
let font_key = FontKey::new(font_name.to_string(), scale, bold, italic); let font_key = FontKey::new(font_name.to_string(), base_size.to_string(), scale, bold, italic);
let key = ShapeKey::new(text.to_string(), font_key); let key = ShapeKey::new(text.to_string(), font_key);
if !self.blob_cache.contains(&key) { if !self.blob_cache.contains(&key) {
self.blob_cache.put(key.clone(), self.shape(text, font_name, scale, bold, italic, &font)); let blob = self.shape(text, font_name, base_size, scale, bold, italic, &font);
self.blob_cache.put(key.clone(), blob);
} }
self.blob_cache.get(&key).unwrap() self.blob_cache.get(&key).unwrap()
@ -97,4 +97,29 @@ impl CachingShaper {
self.font_cache.clear(); self.font_cache.clear();
self.blob_cache.clear(); self.blob_cache.clear();
} }
pub fn font_base_dimensions(&mut self, font_lookup: &mut FontLookup) -> (f32, f32) {
let base_fonts = font_lookup.size(1);
let normal_font = &base_fonts.normal;
let (_, metrics) = normal_font.metrics();
let font_height = metrics.descent - metrics.ascent;
let font_key = FontKey::new(font_lookup.name.to_string(), font_lookup.base_size.to_string(), 1, false, false);
let font_ref = self.get_font(&font_key);
let style = TextStyle { size: font_lookup.base_size };
let layout = layout_run(&style, font_ref, standard_character_string);
let glyph_offsets: Vec<f32> = layout.glyphs.iter().map(|glyph| glyph.offset.x).collect();
let glyph_advances: Vec<f32> = glyph_offsets.windows(2).map(|pair| pair[1] - pair[0]).collect();
let mut amounts = HashMap::new();
for advance in glyph_advances.iter() {
amounts.entry(advance.to_string())
.and_modify(|e| *e += 1)
.or_insert(1);
}
let (font_width, _) = amounts.into_iter().max_by_key(|(_, count)| count.clone()).unwrap();
let font_width = font_width.parse::<f32>().unwrap();
(font_width, font_height)
}
} }

@ -139,8 +139,9 @@ impl CursorRenderer {
.unwrap_or(' '); .unwrap_or(' ');
canvas.save(); canvas.save();
canvas.clip_path(&path, None, Some(false)); canvas.clip_path(&path, None, Some(false));
canvas.draw_text_blob( canvas.draw_text_blob(
shaper.shape_cached(character.to_string(), 1, false, false, &fonts_lookup.size(1).normal), shaper.shape_cached(&character.to_string(), &fonts_lookup.name.clone(), fonts_lookup.base_size, 1, false, false, &fonts_lookup.size(1).normal),
destination, &paint); destination, &paint);
canvas.restore(); canvas.restore();
} }

@ -7,8 +7,6 @@ use skribo::{
}; };
use crate::editor::Style; use crate::editor::Style;
const standard_character_string: &'static str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
pub struct Fonts { pub struct Fonts {
pub name: String, pub name: String,
pub size: f32, pub size: f32,
@ -87,37 +85,4 @@ impl FontLookup {
Fonts::new(&name, base_size * size_multiplier as f32) Fonts::new(&name, base_size * size_multiplier as f32)
}) })
} }
pub fn font_base_dimensions(&mut self) -> (f32, f32) {
let base_fonts = self.size(1);
let normal_font = &base_fonts.normal;
let (_, metrics) = normal_font.metrics();
let font_height = metrics.descent - metrics.ascent;
let source = SystemSource::new();
let font_name = self.name.clone();
let font_size = self.base_size;
let font = source
.select_family_by_name(&font_name)
.expect("Failed to load by postscript name")
.fonts()[0]
.load()
.unwrap();
let font_ref = FontRef::new(font);
let style = TextStyle { size: font_size };
let layout = layout_run(&style, &font_ref, standard_character_string);
let glyph_offsets: Vec<f32> = layout.glyphs.iter().map(|glyph| glyph.offset.x).collect();
let glyph_advances: Vec<f32> = glyph_offsets.windows(2).map(|pair| pair[1] - pair[0]).collect();
let mut amounts = HashMap::new();
for advance in glyph_advances.iter() {
amounts.entry(advance.to_string())
.and_modify(|e| *e += 1)
.or_insert(1);
}
let (font_width, _) = amounts.into_iter().max_by_key(|(_, count)| count.clone()).unwrap();
let font_width = font_width.parse::<f32>().unwrap();
(font_width, font_height)
}
} }

@ -41,10 +41,10 @@ impl Renderer {
let mut paint = Paint::new(colors::WHITE, None); let mut paint = Paint::new(colors::WHITE, None);
paint.set_anti_alias(false); paint.set_anti_alias(false);
let shaper = CachingShaper::new(); let mut shaper = CachingShaper::new();
let mut fonts_lookup = FontLookup::new(DEFAULT_FONT_NAME, DEFAULT_FONT_SIZE); let mut fonts_lookup = FontLookup::new(DEFAULT_FONT_NAME, DEFAULT_FONT_SIZE);
let (font_width, font_height) = fonts_lookup.font_base_dimensions(); let (font_width, font_height) = shaper.font_base_dimensions(&mut fonts_lookup);
let cursor_renderer = CursorRenderer::new(); let cursor_renderer = CursorRenderer::new();
Renderer { editor, surface, paint, fonts_lookup, shaper, font_width, font_height, cursor_renderer } Renderer { editor, surface, paint, fonts_lookup, shaper, font_width, font_height, cursor_renderer }
@ -52,10 +52,10 @@ impl Renderer {
fn set_font(&mut self, name: &str, size: f32) { fn set_font(&mut self, name: &str, size: f32) {
self.fonts_lookup = FontLookup::new(name, size); self.fonts_lookup = FontLookup::new(name, size);
let (font_width, font_height) = self.fonts_lookup.font_base_dimensions(); self.shaper.clear();
let (font_width, font_height) = self.shaper.font_base_dimensions(&mut self.fonts_lookup);
self.font_width = font_width; self.font_width = font_width;
self.font_height = font_height; self.font_height = font_height;
self.shaper.clear();
} }
fn compute_text_region(&self, text: &str, grid_pos: (u64, u64), size: u16) -> Rect { fn compute_text_region(&self, text: &str, grid_pos: (u64, u64), size: u16) -> Rect {
@ -100,8 +100,10 @@ impl Renderer {
self.paint.set_color(style.foreground(&default_colors).to_color()); self.paint.set_color(style.foreground(&default_colors).to_color());
let text = text.trim_end(); let text = text.trim_end();
if text.len() > 0 { if text.len() > 0 {
let font_name = self.fonts_lookup.name.clone();
let font_size = self.fonts_lookup.base_size;
let font = self.fonts_lookup.size(size).get(&style); let font = self.fonts_lookup.size(size).get(&style);
let blob = self.shaper.shape_cached(text.to_string(), size, style.bold, style.italic, font); let blob = self.shaper.shape_cached(text, &font_name, font_size, size, style.bold, style.italic, font);
canvas.draw_text_blob(blob, (x, y), &self.paint); canvas.draw_text_blob(blob, (x, y), &self.paint);
} }

Loading…
Cancel
Save