more progress, but can't use text blob creation utilities :/

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

@ -1,42 +1,100 @@
use lru::LruCache; use lru::LruCache;
use skulpin::skia_safe::{Shaper, TextBlob, Font, Point}; use skulpin::skia_safe::{Shaper, TextBlob, Font, Point, TextBlobBuilder};
use font_kit::source::SystemSource;
use skribo::{
layout, layout_run, make_layout, FontCollection, FontFamily, FontRef, Layout, LayoutSession,
TextStyle
};
#[derive(new, Clone, Hash, PartialEq, Eq)] #[derive(new, Clone, Hash, PartialEq, Eq)]
struct ShapeKey { struct FontKey {
pub text: String, pub name: String,
pub scale: u16, pub scale: u16,
pub bold: bool, pub bold: bool,
pub italic: bool pub italic: bool
} }
#[derive(new, Clone, Hash, PartialEq, Eq)]
struct ShapeKey {
pub text: String,
pub font_key: FontKey
}
pub struct CachingShaper { pub struct CachingShaper {
shaper: Shaper, font_cache: LruCache<FontKey, FontRef>,
cache: LruCache<ShapeKey, TextBlob> blob_cache: LruCache<ShapeKey, TextBlob>
} }
impl CachingShaper { impl CachingShaper {
pub fn new() -> CachingShaper { pub fn new() -> CachingShaper {
CachingShaper { CachingShaper {
shaper: Shaper::new(None), font_cache: LruCache::new(100),
cache: LruCache::new(10000) blob_cache: LruCache::new(10000)
} }
} }
pub fn shape(&self, text: &str, font: &Font) -> TextBlob { fn get_font(&self, font_key: &FontKey) -> &FontRef {
let (blob, _) = self.shaper.shape_text_blob(text, font, true, 1000000.0, Point::default()).unwrap(); if !self.font_cache.contains(font_key) {
blob let source = SystemSource::new();
let font_name = font_key.name.clone();
let font = source
.select_family_by_name(&font_name)
.expect("Failed to load by postscript name")
.fonts()[0]
.load()
.unwrap();
self.font_cache.put(key.clone(), FontRef::new(font));
}
self.font_cache.get(&key).unwrap()
}
pub fn shape(&self, text: &str, font_name: &str, scale: u16, bold: bool, italic: bool, font: &Font) -> TextBlob {
let font_key = FontKey::new(font_name.to_string(), scale, bold, italic);
let font_ref = self.get_font(&font_key);
let style = TextStyle { size: font_size };
let layout = layout_run(&style, &font_ref, standard_character_string);
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()
// 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 glyph_advances: Vec<f32> = glyph_offsets.windows(2).map(|pair| pair[1] - pair[0]).collect();
// let (blob, _) = self.shaper.shape_text_blob(text, font, true, 1000000.0, Point::default()).unwrap();
// blob
} }
pub fn shape_cached(&mut self, text: String, scale: u16, bold: bool, italic: bool, font: &Font) -> &TextBlob { pub fn shape_cached(&mut self, text: &str, font_name: &str, scale: u16, bold: bool, italic: bool, font: &Font) -> &TextBlob {
let key = ShapeKey::new(text.clone(), scale, bold, italic); let font_key = FontKey::new(font_name.to_string(), scale, bold, italic);
if !self.cache.contains(&key) { let key = ShapeKey::new(text.to_string(), font_key);
self.cache.put(key.clone(), self.shape(&text, &font)); if !self.blob_cache.contains(&key) {
self.blob_cache.put(key.clone(), self.shape(text, font_name, scale, bold, italic, &font));
} }
self.cache.get(&key).unwrap() self.blob_cache.get(&key).unwrap()
} }
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.cache.clear(); self.font_cache.clear();
self.blob_cache.clear();
} }
} }

@ -7,7 +7,7 @@ use skribo::{
}; };
use crate::editor::Style; use crate::editor::Style;
const standard_character_string: &'static str = "XXXX"; const standard_character_string: &'static str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
pub struct Fonts { pub struct Fonts {
pub name: String, pub name: String,
@ -106,11 +106,17 @@ impl FontLookup {
let font_ref = FontRef::new(font); let font_ref = FontRef::new(font);
let style = TextStyle { size: font_size }; let style = TextStyle { size: font_size };
let layout = layout_run(&style, &font_ref, standard_character_string); let layout = layout_run(&style, &font_ref, standard_character_string);
let font_width = layout.advance.x / standard_character_string.len() as f32; let glyph_offsets: Vec<f32> = layout.glyphs.iter().map(|glyph| glyph.offset.x).collect();
// 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 glyph_advances: Vec<f32> = glyph_offsets.windows(2).map(|pair| pair[1] - pair[0]).collect();
// dbg!(&glyph_advances); let mut amounts = HashMap::new();
// let font_width = glyph_advances.iter().cloned().fold(0.0, f32::max); 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) (font_width, font_height)
} }

Loading…
Cancel
Save