Reduce allocations when caching fonts

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2022-04-13 19:06:34 +02:00
parent cdcdccfb89
commit 8e89074714

View file

@ -9,6 +9,7 @@ use crate::{
text_layout::{Glyph, LineLayout, Run, RunStyle}, text_layout::{Glyph, LineLayout, Run, RunStyle},
}; };
use cocoa::appkit::{CGFloat, CGPoint}; use cocoa::appkit::{CGFloat, CGPoint};
use collections::HashMap;
use core_foundation::{ use core_foundation::{
array::CFIndex, array::CFIndex,
attributed_string::{CFAttributedStringRef, CFMutableAttributedString}, attributed_string::{CFAttributedStringRef, CFMutableAttributedString},
@ -36,19 +37,19 @@ struct FontSystemState {
memory_source: MemSource, memory_source: MemSource,
system_source: SystemSource, system_source: SystemSource,
fonts: Vec<font_kit::font::Font>, fonts: Vec<font_kit::font::Font>,
emoji_font_id: FontId, font_ids_by_postscript_name: HashMap<String, FontId>,
postscript_names_by_font_id: HashMap<FontId, String>,
} }
impl FontSystem { impl FontSystem {
pub fn new() -> Self { pub fn new() -> Self {
let mut state = FontSystemState { Self(RwLock::new(FontSystemState {
memory_source: MemSource::empty(), memory_source: MemSource::empty(),
system_source: SystemSource::new(), system_source: SystemSource::new(),
fonts: Vec::new(), fonts: Vec::new(),
emoji_font_id: FontId(0), // This will be the first font that we load. font_ids_by_postscript_name: Default::default(),
}; postscript_names_by_font_id: Default::default(),
state.load_family("Apple Color Emoji").unwrap(); }))
Self(RwLock::new(state))
} }
} }
@ -128,7 +129,13 @@ impl FontSystemState {
.or_else(|_| self.system_source.select_family_by_name(name))?; .or_else(|_| self.system_source.select_family_by_name(name))?;
for font in family.fonts() { for font in family.fonts() {
let font = font.load()?; let font = font.load()?;
font_ids.push(FontId(self.fonts.len())); let font_id = FontId(self.fonts.len());
font_ids.push(font_id);
let postscript_name = font.postscript_name().unwrap();
self.font_ids_by_postscript_name
.insert(postscript_name.clone(), font_id);
self.postscript_names_by_font_id
.insert(font_id, postscript_name);
self.fonts.push(font); self.fonts.push(font);
} }
Ok(font_ids) Ok(font_ids)
@ -159,17 +166,30 @@ impl FontSystemState {
self.fonts[font_id.0].glyph_for_char(ch) self.fonts[font_id.0].glyph_for_char(ch)
} }
fn id_for_font(&mut self, requested_font: font_kit::font::Font) -> FontId { fn id_for_native_font(&mut self, requested_font: CTFont) -> FontId {
// TODO: don't allocate the postscript name let postscript_name = requested_font.postscript_name();
// Note: Coretext always returns a Some option for postscript_name if let Some(font_id) = self.font_ids_by_postscript_name.get(&postscript_name) {
let requested_font_name = requested_font.postscript_name(); *font_id
for (id, font) in self.fonts.iter().enumerate() { } else {
if font.postscript_name() == requested_font_name { let font_id = FontId(self.fonts.len());
return FontId(id); self.font_ids_by_postscript_name
} .insert(postscript_name.clone(), font_id);
self.postscript_names_by_font_id
.insert(font_id, postscript_name);
self.fonts
.push(font_kit::font::Font::from_core_graphics_font(
requested_font.copy_to_CGFont(),
));
font_id
} }
self.fonts.push(requested_font); }
FontId(self.fonts.len() - 1)
fn is_emoji(&self, font_id: FontId) -> bool {
self.postscript_names_by_font_id
.get(&font_id)
.map_or(false, |postscript_name| {
postscript_name == "AppleColorEmoji"
})
} }
fn rasterize_glyph( fn rasterize_glyph(
@ -340,13 +360,12 @@ impl FontSystemState {
for run in line.glyph_runs().into_iter() { for run in line.glyph_runs().into_iter() {
let attributes = run.attributes().unwrap(); let attributes = run.attributes().unwrap();
let font = unsafe { let font = unsafe {
let native_font = attributes attributes
.get(kCTFontAttributeName) .get(kCTFontAttributeName)
.downcast::<CTFont>() .downcast::<CTFont>()
.unwrap(); .unwrap()
font_kit::font::Font::from_native_font(native_font)
}; };
let font_id = self.id_for_font(font); let font_id = self.id_for_native_font(font);
let mut ix_converter = StringIndexConverter::new(text); let mut ix_converter = StringIndexConverter::new(text);
let mut glyphs = Vec::new(); let mut glyphs = Vec::new();
@ -362,7 +381,7 @@ impl FontSystemState {
id: *glyph_id as GlyphId, id: *glyph_id as GlyphId,
position: vec2f(position.x as f32, position.y as f32), position: vec2f(position.x as f32, position.y as f32),
index: ix_converter.utf8_ix, index: ix_converter.utf8_ix,
is_emoji: font_id == self.emoji_font_id, is_emoji: self.is_emoji(font_id),
}); });
} }