Cache rustybuzz shape plans.
This commit is contained in:
parent
94e6cdefda
commit
73acfb0962
7 changed files with 98 additions and 17 deletions
|
|
@ -18,7 +18,7 @@ log = "0.4.20"
|
|||
modit = { version = "0.1.3", optional = true }
|
||||
rangemap = "1.4.0"
|
||||
rustc-hash = { version = "1.1.0", default-features = false }
|
||||
rustybuzz = { version = "0.11.0", default-features = false, features = ["libm"] }
|
||||
rustybuzz = { version = "0.12.0", default-features = false, features = ["libm"] }
|
||||
self_cell = "1.0.1"
|
||||
swash = { version = "0.1.8", optional = true }
|
||||
syntect = { version = "5.1.0", optional = true }
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use alloc::vec::Vec;
|
|||
use fontdb::Family;
|
||||
use unicode_script::Script;
|
||||
|
||||
use crate::{Font, FontSystem};
|
||||
use crate::{Font, FontSystem, ShapePlanCache};
|
||||
|
||||
use self::platform::*;
|
||||
|
||||
|
|
@ -103,6 +103,10 @@ impl<'a> FontFallbackIter<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn shape_plan_cache(&mut self) -> &mut ShapePlanCache {
|
||||
self.font_system.shape_plan_cache()
|
||||
}
|
||||
|
||||
fn face_contains_family(&self, id: fontdb::ID, family_name: &str) -> bool {
|
||||
if let Some(face) = self.font_system.db().face(id) {
|
||||
face.families.iter().any(|(name, _)| name == family_name)
|
||||
|
|
|
|||
|
|
@ -1,17 +1,10 @@
|
|||
use crate::{Attrs, AttrsOwned, Font};
|
||||
use crate::{Attrs, AttrsOwned, Font, HashMap, ShapePlanCache};
|
||||
use alloc::string::String;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
type BuildHasher = core::hash::BuildHasherDefault<rustc_hash::FxHasher>;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
type HashMap<K, V> = std::collections::HashMap<K, V, BuildHasher>;
|
||||
#[cfg(not(feature = "std"))]
|
||||
type HashMap<K, V> = hashbrown::HashMap<K, V, BuildHasher>;
|
||||
|
||||
// re-export fontdb and rustybuzz
|
||||
pub use fontdb;
|
||||
pub use rustybuzz;
|
||||
|
|
@ -29,6 +22,9 @@ pub struct FontSystem {
|
|||
|
||||
/// Cache for font matches.
|
||||
font_matches_cache: HashMap<AttrsOwned, Arc<Vec<fontdb::ID>>>,
|
||||
|
||||
/// Cache for rustybuzz shape plans.
|
||||
shape_plan_cache: ShapePlanCache,
|
||||
}
|
||||
|
||||
impl fmt::Debug for FontSystem {
|
||||
|
|
@ -74,8 +70,9 @@ impl FontSystem {
|
|||
Self {
|
||||
locale,
|
||||
db,
|
||||
font_cache: HashMap::default(),
|
||||
font_matches_cache: HashMap::default(),
|
||||
font_cache: Default::default(),
|
||||
font_matches_cache: Default::default(),
|
||||
shape_plan_cache: ShapePlanCache::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,6 +86,11 @@ impl FontSystem {
|
|||
&self.db
|
||||
}
|
||||
|
||||
/// Get the shape plan cache.
|
||||
pub(crate) fn shape_plan_cache(&mut self) -> &mut ShapePlanCache {
|
||||
&mut self.shape_plan_cache
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the database.
|
||||
pub fn db_mut(&mut self) -> &mut fontdb::Database {
|
||||
self.font_matches_cache.clear();
|
||||
|
|
|
|||
14
src/lib.rs
14
src/lib.rs
|
|
@ -108,8 +108,8 @@ mod buffer;
|
|||
pub use self::buffer_line::*;
|
||||
mod buffer_line;
|
||||
|
||||
pub use self::cache::*;
|
||||
mod cache;
|
||||
pub use self::glyph_cache::*;
|
||||
mod glyph_cache;
|
||||
|
||||
pub use self::edit::*;
|
||||
mod edit;
|
||||
|
|
@ -123,7 +123,17 @@ mod layout;
|
|||
pub use self::shape::*;
|
||||
mod shape;
|
||||
|
||||
use self::shape_plan_cache::*;
|
||||
mod shape_plan_cache;
|
||||
|
||||
#[cfg(feature = "swash")]
|
||||
pub use self::swash::*;
|
||||
#[cfg(feature = "swash")]
|
||||
mod swash;
|
||||
|
||||
type BuildHasher = core::hash::BuildHasherDefault<rustc_hash::FxHasher>;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
type HashMap<K, V> = std::collections::HashMap<K, V, BuildHasher>;
|
||||
#[cfg(not(feature = "std"))]
|
||||
type HashMap<K, V> = hashbrown::HashMap<K, V, BuildHasher>;
|
||||
|
|
|
|||
19
src/shape.rs
19
src/shape.rs
|
|
@ -12,7 +12,9 @@ use unicode_script::{Script, UnicodeScript};
|
|||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
use crate::fallback::FontFallbackIter;
|
||||
use crate::{Align, AttrsList, Color, Font, FontSystem, LayoutGlyph, LayoutLine, Wrap};
|
||||
use crate::{
|
||||
Align, AttrsList, Color, Font, FontSystem, LayoutGlyph, LayoutLine, ShapePlanCache, Wrap,
|
||||
};
|
||||
|
||||
/// The shaping strategy of some text.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
|
@ -85,6 +87,7 @@ impl fmt::Debug for ShapeBuffer {
|
|||
fn shape_fallback(
|
||||
scratch: &mut ShapeBuffer,
|
||||
glyphs: &mut Vec<ShapeGlyph>,
|
||||
shape_plan_cache: &mut ShapePlanCache,
|
||||
font: &Font,
|
||||
line: &str,
|
||||
attrs_list: &AttrsList,
|
||||
|
|
@ -110,7 +113,8 @@ fn shape_fallback(
|
|||
let rtl = matches!(buffer.direction(), rustybuzz::Direction::RightToLeft);
|
||||
assert_eq!(rtl, span_rtl);
|
||||
|
||||
let glyph_buffer = rustybuzz::shape(font.rustybuzz(), &[], buffer);
|
||||
let shape_plan = shape_plan_cache.get(font, &buffer);
|
||||
let glyph_buffer = rustybuzz::shape_with_plan(font.rustybuzz(), shape_plan, buffer);
|
||||
let glyph_infos = glyph_buffer.glyph_infos();
|
||||
let glyph_positions = glyph_buffer.glyph_positions();
|
||||
|
||||
|
|
@ -218,7 +222,15 @@ fn shape_run(
|
|||
|
||||
let glyph_start = glyphs.len();
|
||||
let mut missing = shape_fallback(
|
||||
scratch, glyphs, &font, line, attrs_list, start_run, end_run, span_rtl,
|
||||
scratch,
|
||||
glyphs,
|
||||
font_iter.shape_plan_cache(),
|
||||
&font,
|
||||
line,
|
||||
attrs_list,
|
||||
start_run,
|
||||
end_run,
|
||||
span_rtl,
|
||||
);
|
||||
|
||||
//TODO: improve performance!
|
||||
|
|
@ -236,6 +248,7 @@ fn shape_run(
|
|||
let fb_missing = shape_fallback(
|
||||
scratch,
|
||||
&mut fb_glyphs,
|
||||
font_iter.shape_plan_cache(),
|
||||
&font,
|
||||
line,
|
||||
attrs_list,
|
||||
|
|
|
|||
52
src/shape_plan_cache.rs
Normal file
52
src/shape_plan_cache.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
use std::collections::hash_map::Entry;
|
||||
|
||||
use crate::{Font, HashMap};
|
||||
|
||||
/// Key for caching shape plans.
|
||||
#[derive(Debug, Hash, PartialEq, Eq)]
|
||||
struct ShapePlanKey {
|
||||
font_id: fontdb::ID,
|
||||
direction: rustybuzz::Direction,
|
||||
script: rustybuzz::Script,
|
||||
language: Option<rustybuzz::Language>,
|
||||
}
|
||||
|
||||
/// A helper structure for caching rustybuzz shape plans.
|
||||
#[derive(Default)]
|
||||
pub struct ShapePlanCache(HashMap<ShapePlanKey, rustybuzz::ShapePlan>);
|
||||
|
||||
impl ShapePlanCache {
|
||||
pub fn get(&mut self, font: &Font, buffer: &rustybuzz::UnicodeBuffer) -> &rustybuzz::ShapePlan {
|
||||
let key = ShapePlanKey {
|
||||
font_id: font.id(),
|
||||
direction: buffer.direction(),
|
||||
script: buffer.script(),
|
||||
language: buffer.language(),
|
||||
};
|
||||
match self.0.entry(key) {
|
||||
Entry::Occupied(occ) => occ.into_mut(),
|
||||
Entry::Vacant(vac) => {
|
||||
let ShapePlanKey {
|
||||
direction,
|
||||
script,
|
||||
language,
|
||||
..
|
||||
} = vac.key();
|
||||
let plan = rustybuzz::ShapePlan::new(
|
||||
font.rustybuzz(),
|
||||
*direction,
|
||||
Some(*script),
|
||||
language.as_ref(),
|
||||
&[],
|
||||
);
|
||||
vac.insert(plan)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ShapePlanCache {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_tuple("ShapePlanCache").finish()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue