Reduce allocations when caching fonts
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
cdcdccfb89
commit
8e89074714
1 changed files with 41 additions and 22 deletions
|
@ -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),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue