Remove Mutex from FontSystem

This commit is contained in:
Edgar Geier 2023-03-12 10:30:20 +01:00
parent 46e9ef0246
commit 384c5c1fdc
No known key found for this signature in database
GPG key ID: DE2B55319457EB56
16 changed files with 109 additions and 96 deletions

View file

@ -139,7 +139,10 @@ impl Application for Window {
.family(cosmic_text::Family::Monospace);
let mut editor = SyntaxEditor::new(
Buffer::new(&FONT_SYSTEM.lock().unwrap(), FontSize::Body.to_metrics()),
Buffer::new(
&mut FONT_SYSTEM.lock().unwrap(),
FontSize::Body.to_metrics(),
),
&SYNTAX_SYSTEM,
"base16-eighties.dark",
)

View file

@ -53,7 +53,7 @@ impl Text {
let mut line = BufferLine::new(string, AttrsList::new(Attrs::new()));
//TODO: do we have to immediately shape?
line.shape(&FONT_SYSTEM.lock().unwrap());
line.shape(&mut FONT_SYSTEM.lock().unwrap());
let text = Self {
line,
@ -186,7 +186,7 @@ where
};
cache.with_pixels(
&FONT_SYSTEM.lock().unwrap(),
&mut FONT_SYSTEM.lock().unwrap(),
cache_key,
glyph_color,
|pixel_x, pixel_y, color| {

View file

@ -58,7 +58,7 @@ fn main() {
let line_x = 8.0 * display_scale;
let mut editor = SyntaxEditor::new(
Buffer::new(&font_system, font_sizes[font_size_i]),
Buffer::new(&mut font_system, font_sizes[font_size_i]),
&syntax_system,
"base16-eighties.dark",
)

View file

@ -60,7 +60,7 @@ fn main() {
];
let font_size_default = 1; // Body
let mut buffer = Buffer::new(&font_system, font_sizes[font_size_default]);
let mut buffer = Buffer::new(&mut font_system, font_sizes[font_size_default]);
buffer
.borrow_with(&mut font_system)
.set_size(window.width() as f32, window.height() as f32);

View file

@ -37,7 +37,7 @@ fn main() {
.unwrap();
let mut editor = Editor::new(Buffer::new(
&font_system,
&mut font_system,
Metrics::new(32.0, 44.0).scale(display_scale),
));

View file

@ -15,7 +15,7 @@ fn main() {
let metrics = Metrics::new(14.0, 20.0);
// A Buffer provides shaping and layout for a UTF-8 string, create one per text widget
let mut buffer = Buffer::new(&font_system, metrics);
let mut buffer = Buffer::new(&mut font_system, metrics);
let mut buffer = buffer.borrow_with(&mut font_system);

View file

@ -317,7 +317,7 @@ impl Buffer {
/// # Panics
///
/// Will panic if `metrics.line_height` is zero.
pub fn new(font_system: &FontSystem, metrics: Metrics) -> Self {
pub fn new(font_system: &mut FontSystem, metrics: Metrics) -> Self {
assert_ne!(metrics.line_height, 0.0, "line height cannot be 0");
let mut buffer = Self {
@ -343,7 +343,7 @@ impl Buffer {
}
}
pub(crate) fn relayout(&mut self, font_system: &FontSystem) {
pub(crate) fn relayout(&mut self, font_system: &mut FontSystem) {
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
let instant = std::time::Instant::now();
@ -360,7 +360,7 @@ impl Buffer {
log::debug!("relayout: {:?}", instant.elapsed());
}
pub(crate) fn shape_until(&mut self, font_system: &FontSystem, lines: i32) -> i32 {
pub(crate) fn shape_until(&mut self, font_system: &mut FontSystem, lines: i32) -> i32 {
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
let instant = std::time::Instant::now();
@ -387,7 +387,7 @@ impl Buffer {
total_layout
}
pub(crate) fn shape_until_cursor(&mut self, font_system: &FontSystem, cursor: Cursor) {
pub(crate) fn shape_until_cursor(&mut self, font_system: &mut FontSystem, cursor: Cursor) {
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
let instant = std::time::Instant::now();
@ -427,7 +427,7 @@ impl Buffer {
self.shape_until_scroll(font_system);
}
pub(crate) fn shape_until_scroll(&mut self, font_system: &FontSystem) {
pub(crate) fn shape_until_scroll(&mut self, font_system: &mut FontSystem) {
let lines = self.visible_lines();
let scroll_end = self.scroll + lines;
@ -468,7 +468,7 @@ impl Buffer {
pub(crate) fn line_shape(
&mut self,
font_system: &FontSystem,
font_system: &mut FontSystem,
line_i: usize,
) -> Option<&ShapeLine> {
let line = self.lines.get_mut(line_i)?;
@ -477,7 +477,7 @@ impl Buffer {
pub(crate) fn line_layout(
&mut self,
font_system: &FontSystem,
font_system: &mut FontSystem,
line_i: usize,
) -> Option<&[LayoutLine]> {
let line = self.lines.get_mut(line_i)?;
@ -489,7 +489,7 @@ impl Buffer {
self.metrics
}
fn set_metrics(&mut self, font_system: &FontSystem, metrics: Metrics) {
fn set_metrics(&mut self, font_system: &mut FontSystem, metrics: Metrics) {
if metrics != self.metrics {
assert_ne!(metrics.font_size, 0.0, "font size cannot be 0");
self.metrics = metrics;
@ -503,7 +503,7 @@ impl Buffer {
self.wrap
}
pub(crate) fn set_wrap(&mut self, font_system: &FontSystem, wrap: Wrap) {
pub(crate) fn set_wrap(&mut self, font_system: &mut FontSystem, wrap: Wrap) {
if wrap != self.wrap {
self.wrap = wrap;
self.relayout(font_system);
@ -516,7 +516,7 @@ impl Buffer {
(self.width, self.height)
}
pub(crate) fn set_size(&mut self, font_system: &FontSystem, width: f32, height: f32) {
pub(crate) fn set_size(&mut self, font_system: &mut FontSystem, width: f32, height: f32) {
let clamped_width = width.max(0.0);
let clamped_height = height.max(0.0);
@ -546,7 +546,7 @@ impl Buffer {
(self.height / self.metrics.line_height) as i32
}
pub(crate) fn set_text(&mut self, font_system: &FontSystem, text: &str, attrs: Attrs) {
pub(crate) fn set_text(&mut self, font_system: &mut FontSystem, text: &str, attrs: Attrs) {
self.lines.clear();
for line in text.lines() {
self.lines
@ -682,7 +682,7 @@ impl Buffer {
#[cfg(feature = "swash")]
pub(crate) fn draw<F>(
&self,
font_system: &FontSystem,
font_system: &mut FontSystem,
cache: &mut crate::SwashCache,
color: Color,
mut f: F,
@ -758,7 +758,7 @@ impl<'a> BorrowedWithFontSystem<'a, Buffer> {
/// Draw the buffer
#[cfg(feature = "swash")]
pub fn draw<F>(&self, cache: &mut crate::SwashCache, color: Color, f: F)
pub fn draw<F>(&mut self, cache: &mut crate::SwashCache, color: Color, f: F)
where
F: FnMut(i32, i32, u32, u32, Color),
{

View file

@ -167,7 +167,7 @@ impl BufferLine {
}
/// Shape line, will cache results
pub fn shape(&mut self, font_system: &FontSystem) -> &ShapeLine {
pub fn shape(&mut self, font_system: &mut FontSystem) -> &ShapeLine {
if self.shape_opt.is_none() {
self.shape_opt = Some(ShapeLine::new(font_system, &self.text, &self.attrs_list));
self.layout_opt = None;
@ -183,7 +183,7 @@ impl BufferLine {
/// Layout line, will cache results
pub fn layout(
&mut self,
font_system: &FontSystem,
font_system: &mut FontSystem,
font_size: f32,
width: f32,
wrap: Wrap,

View file

@ -35,7 +35,7 @@ impl Editor {
}
}
fn set_layout_cursor(&mut self, font_system: &FontSystem, cursor: LayoutCursor) {
pub(crate) fn set_layout_cursor(&mut self, font_system: &mut FontSystem, cursor: LayoutCursor) {
let layout = self
.buffer
.line_layout(font_system, cursor.line)
@ -94,7 +94,7 @@ impl Edit for Editor {
}
}
fn shape_as_needed(&mut self, font_system: &FontSystem) {
fn shape_as_needed(&mut self, font_system: &mut FontSystem) {
if self.cursor_moved {
self.buffer.shape_until_cursor(font_system, self.cursor);
self.cursor_moved = false;
@ -281,7 +281,7 @@ impl Edit for Editor {
self.cursor.index = self.buffer.lines[self.cursor.line].text().len() - after_len;
}
fn action(&mut self, font_system: &FontSystem, action: Action) {
fn action(&mut self, font_system: &mut FontSystem, action: Action) {
let old_cursor = self.cursor;
match action {
@ -677,7 +677,7 @@ impl Edit for Editor {
#[cfg(feature = "swash")]
fn draw<F>(
&self,
font_system: &FontSystem,
font_system: &mut FontSystem,
cache: &mut crate::SwashCache,
color: Color,
mut f: F,

View file

@ -108,7 +108,7 @@ pub trait Edit {
fn set_select_opt(&mut self, select_opt: Option<Cursor>);
/// Shape lines until scroll, after adjusting scroll if the cursor moved
fn shape_as_needed(&mut self, font_system: &FontSystem);
fn shape_as_needed(&mut self, font_system: &mut FontSystem);
/// Copy selection
fn copy_selection(&mut self) -> Option<String>;
@ -122,12 +122,17 @@ pub trait Edit {
fn insert_string(&mut self, data: &str, attrs_list: Option<AttrsList>);
/// Perform an [Action] on the editor
fn action(&mut self, font_system: &FontSystem, action: Action);
fn action(&mut self, font_system: &mut FontSystem, action: Action);
/// Draw the editor
#[cfg(feature = "swash")]
fn draw<F>(&self, font_system: &FontSystem, cache: &mut crate::SwashCache, color: Color, f: F)
where
fn draw<F>(
&self,
font_system: &mut FontSystem,
cache: &mut crate::SwashCache,
color: Color,
f: F,
) where
F: FnMut(i32, i32, u32, u32, Color);
}
@ -152,7 +157,7 @@ impl<'a, T: Edit> BorrowedWithFontSystem<'a, T> {
/// Draw the editor
#[cfg(feature = "swash")]
pub fn draw<F>(&self, cache: &mut crate::SwashCache, color: Color, f: F)
pub fn draw<F>(&mut self, cache: &mut crate::SwashCache, color: Color, f: F)
where
F: FnMut(i32, i32, u32, u32, Color),
{

View file

@ -63,7 +63,7 @@ impl<'a> SyntaxEditor<'a> {
#[cfg(feature = "std")]
pub(crate) fn load_text<P: AsRef<Path>>(
&mut self,
font_system: &FontSystem,
font_system: &mut FontSystem,
path: P,
attrs: crate::Attrs,
) -> io::Result<()> {
@ -131,7 +131,7 @@ impl<'a> Edit for SyntaxEditor<'a> {
self.editor.set_select_opt(select_opt);
}
fn shape_as_needed(&mut self, font_system: &FontSystem) {
fn shape_as_needed(&mut self, font_system: &mut FontSystem) {
#[cfg(feature = "std")]
let now = std::time::Instant::now();
@ -236,7 +236,7 @@ impl<'a> Edit for SyntaxEditor<'a> {
self.editor.insert_string(data, attrs_list);
}
fn action(&mut self, font_system: &FontSystem, action: Action) {
fn action(&mut self, font_system: &mut FontSystem, action: Action) {
self.editor.action(font_system, action);
}
@ -244,7 +244,7 @@ impl<'a> Edit for SyntaxEditor<'a> {
#[cfg(feature = "swash")]
fn draw<F>(
&self,
font_system: &FontSystem,
font_system: &mut FontSystem,
cache: &mut crate::SwashCache,
_color: Color,
mut f: F,

View file

@ -32,7 +32,7 @@ impl<'a> ViEditor<'a> {
#[cfg(feature = "std")]
pub(crate) fn load_text<P: AsRef<std::path::Path>>(
&mut self,
font_system: &FontSystem,
font_system: &mut FontSystem,
path: P,
attrs: crate::Attrs,
) -> std::io::Result<()> {
@ -71,7 +71,7 @@ impl<'a> Edit for ViEditor<'a> {
self.editor.set_select_opt(select_opt);
}
fn shape_as_needed(&mut self, font_system: &FontSystem) {
fn shape_as_needed(&mut self, font_system: &mut FontSystem) {
self.editor.shape_as_needed(font_system);
}
@ -87,7 +87,7 @@ impl<'a> Edit for ViEditor<'a> {
self.editor.insert_string(data, attrs_list);
}
fn action(&mut self, font_system: &FontSystem, action: Action) {
fn action(&mut self, font_system: &mut FontSystem, action: Action) {
let old_mode = self.mode;
match self.mode {
@ -229,7 +229,7 @@ impl<'a> Edit for ViEditor<'a> {
#[cfg(feature = "swash")]
fn draw<F>(
&self,
font_system: &FontSystem,
font_system: &mut FontSystem,
cache: &mut crate::SwashCache,
color: Color,
mut f: F,

View file

@ -44,24 +44,17 @@ impl FontSystem {
}
pub fn get_font(&self, id: fontdb::ID) -> Option<Arc<Font>> {
let face = self.db.face(id)?;
match Font::new(face) {
Some(font) => Some(Arc::new(font)),
None => {
log::warn!("failed to load font '{}'", face.post_script_name);
None
}
}
get_font(&self.db, id)
}
pub fn get_font_matches(&self, attrs: Attrs) -> Arc<Vec<Arc<Font>>> {
pub fn get_font_matches(&mut self, attrs: Attrs) -> Arc<Vec<Arc<Font>>> {
let mut fonts = Vec::new();
for face in self.db.faces() {
if !attrs.matches(face) {
continue;
}
if let Some(font) = self.get_font(face.id) {
if let Some(font) = get_font(&self.db, face.id) {
fonts.push(font);
}
}
@ -69,3 +62,14 @@ impl FontSystem {
Arc::new(fonts)
}
}
fn get_font(db: &fontdb::Database, id: fontdb::ID) -> Option<Arc<Font>> {
let face = db.face(id)?;
match Font::new(face) {
Some(font) => Some(Arc::new(font)),
None => {
log::warn!("failed to load font '{}'", face.post_script_name);
None
}
}
}

View file

@ -1,9 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
use std::{collections::HashMap, sync::Arc};
use crate::{Attrs, AttrsOwned, Font};
@ -11,8 +8,8 @@ use crate::{Attrs, AttrsOwned, Font};
pub struct FontSystem {
locale: String,
db: fontdb::Database,
font_cache: Mutex<HashMap<fontdb::ID, Option<Arc<Font>>>>,
font_matches_cache: Mutex<HashMap<AttrsOwned, Arc<Vec<Arc<Font>>>>>,
font_cache: HashMap<fontdb::ID, Option<Arc<Font>>>,
font_matches_cache: HashMap<AttrsOwned, Arc<Vec<Arc<Font>>>>,
}
impl FontSystem {
@ -88,8 +85,8 @@ impl FontSystem {
Self {
locale,
db,
font_cache: Mutex::new(HashMap::new()),
font_matches_cache: Mutex::new(HashMap::new()),
font_cache: HashMap::new(),
font_matches_cache: HashMap::new(),
}
}
@ -105,44 +102,28 @@ impl FontSystem {
(self.locale, self.db)
}
pub fn get_font(&self, id: fontdb::ID) -> Option<Arc<Font>> {
self.font_cache
.lock()
.expect("failed to lock font cache")
.entry(id)
.or_insert_with(|| {
let face = self.db.face(id)?;
match Font::new(face) {
Some(font) => Some(Arc::new(font)),
None => {
log::warn!("failed to load font '{}'", face.post_script_name);
None
}
}
})
.clone()
pub fn get_font(&mut self, id: fontdb::ID) -> Option<Arc<Font>> {
get_font(&mut self.font_cache, &mut self.db, id)
}
pub fn get_font_matches(&self, attrs: Attrs) -> Arc<Vec<Arc<Font>>> {
pub fn get_font_matches(&mut self, attrs: Attrs) -> Arc<Vec<Arc<Font>>> {
self.font_matches_cache
.lock()
.expect("failed to lock font matches cache")
//TODO: do not create AttrsOwned unless entry does not already exist
.entry(AttrsOwned::new(attrs))
.or_insert_with(|| {
#[cfg(not(target_arch = "wasm32"))]
let now = std::time::Instant::now();
let mut fonts = Vec::new();
for face in self.db.faces() {
if !attrs.matches(face) {
continue;
}
if let Some(font) = self.get_font(face.id) {
fonts.push(font);
}
}
let ids = self
.db
.faces()
.filter(|face| attrs.matches(face))
.map(|face| face.id)
.collect::<Vec<_>>();
let fonts = ids
.into_iter()
.filter_map(|id| get_font(&mut self.font_cache, &mut self.db, id))
.collect();
#[cfg(not(target_arch = "wasm32"))]
{
@ -155,3 +136,23 @@ impl FontSystem {
.clone()
}
}
fn get_font(
font_cache: &mut HashMap<fontdb::ID, Option<Arc<Font>>>,
db: &mut fontdb::Database,
id: fontdb::ID,
) -> Option<Arc<Font>> {
font_cache
.entry(id)
.or_insert_with(|| {
let face = db.face(id)?;
match Font::new(face) {
Some(font) => Some(Arc::new(font)),
None => {
log::warn!("failed to load font '{}'", face.post_script_name);
None
}
}
})
.clone()
}

View file

@ -99,7 +99,7 @@ fn shape_fallback(
}
fn shape_run(
font_system: &FontSystem,
font_system: &mut FontSystem,
line: &str,
attrs_list: &AttrsList,
start_run: usize,
@ -273,7 +273,7 @@ pub struct ShapeWord {
impl ShapeWord {
pub fn new(
font_system: &FontSystem,
font_system: &mut FontSystem,
line: &str,
attrs_list: &AttrsList,
word_range: Range<usize>,
@ -347,7 +347,7 @@ pub struct ShapeSpan {
impl ShapeSpan {
pub fn new(
font_system: &FontSystem,
font_system: &mut FontSystem,
line: &str,
attrs_list: &AttrsList,
span_range: Range<usize>,
@ -431,7 +431,7 @@ impl ShapeLine {
/// # Panics
///
/// Will panic if `line` contains more than one paragraph.
pub fn new(font_system: &FontSystem, line: &str, attrs_list: &AttrsList) -> Self {
pub fn new(font_system: &mut FontSystem, line: &str, attrs_list: &AttrsList) -> Self {
let mut spans = Vec::new();
let bidi = unicode_bidi::BidiInfo::new(line, None);

View file

@ -16,7 +16,7 @@ pub use swash::scale::image::{Content as SwashContent, Image as SwashImage};
pub use swash::zeno::{Command, Placement};
fn swash_image(
font_system: &FontSystem,
font_system: &mut FontSystem,
context: &mut ScaleContext,
cache_key: CacheKey,
) -> Option<SwashImage> {
@ -57,7 +57,7 @@ fn swash_image(
}
fn swash_outline_commands(
font_system: &FontSystem,
font_system: &mut FontSystem,
context: &mut ScaleContext,
cache_key: CacheKey,
) -> Option<Vec<swash::zeno::Command>> {
@ -109,7 +109,7 @@ impl SwashCache {
/// Create a swash Image from a cache key, without caching results
pub fn get_image_uncached(
&mut self,
font_system: &FontSystem,
font_system: &mut FontSystem,
cache_key: CacheKey,
) -> Option<SwashImage> {
swash_image(font_system, &mut self.context, cache_key)
@ -118,7 +118,7 @@ impl SwashCache {
/// Create a swash Image from a cache key, caching results
pub fn get_image(
&mut self,
font_system: &FontSystem,
font_system: &mut FontSystem,
cache_key: CacheKey,
) -> &Option<SwashImage> {
self.image_cache
@ -128,7 +128,7 @@ impl SwashCache {
pub fn get_outline_commands(
&mut self,
font_system: &FontSystem,
font_system: &mut FontSystem,
cache_key: CacheKey,
) -> Option<&[swash::zeno::Command]> {
self.outline_command_cache
@ -140,7 +140,7 @@ impl SwashCache {
/// Enumerate pixels in an Image, use `with_image` for better performance
pub fn with_pixels<F: FnMut(i32, i32, Color)>(
&mut self,
font_system: &FontSystem,
font_system: &mut FontSystem,
cache_key: CacheKey,
base: Color,
mut f: F,