Skip to content

Commit

Permalink
feat: support lru cache to limit registry memory usage
Browse files Browse the repository at this point in the history
  • Loading branch information
zimond committed Nov 26, 2024
1 parent 55fc925 commit 10ea022
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 114 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fontkit-rs",
"version": "0.0.14-beta.1",
"version": "0.0.14",
"description": "Toolkit used to load, match, measure, and render texts",
"main": "index.js",
"directories": {
Expand Down
128 changes: 73 additions & 55 deletions src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1426,6 +1426,16 @@ pub mod exports {
}
#[doc(hidden)]
#[allow(non_snake_case)]
pub unsafe fn _export_method_font_kit_set_lru_limit_cabi<T: GuestFontKit>(
arg0: *mut u8,
arg1: i32,
) {
#[cfg(target_arch = "wasm32")]
_rt::run_ctors_once();
T::set_lru_limit(FontKitBorrow::lift(arg0 as u32 as usize).get(), arg1 as u32);
}
#[doc(hidden)]
#[allow(non_snake_case)]
pub unsafe fn _export_method_font_kit_add_font_from_buffer_cabi<T: GuestFontKit>(
arg0: *mut u8,
arg1: *mut u8,
Expand Down Expand Up @@ -2727,6 +2737,9 @@ pub mod exports {
}

fn new() -> Self;
/// add an LRU limit for font buffer registry, `limit`'s
/// unit is KB, 0 means caching is disabled
fn set_lru_limit(&self, limit: u32);
/// Register a font (or several fonts in case of ttc),
/// return the keys of added fonts.
/// The file type is extracted from the buffer by checking
Expand Down Expand Up @@ -2949,6 +2962,10 @@ pub mod exports {
unsafe extern "C" fn export_constructor_font_kit() -> i32 {
$($path_to_types)*::_export_constructor_font_kit_cabi::<<$ty as $($path_to_types)*::Guest>::FontKit>()
}
#[export_name = "alibaba:fontkit/fontkit-interface#[method]font-kit.set-lru-limit"]
unsafe extern "C" fn export_method_font_kit_set_lru_limit(arg0: *mut u8,arg1: i32,) {
$($path_to_types)*::_export_method_font_kit_set_lru_limit_cabi::<<$ty as $($path_to_types)*::Guest>::FontKit>(arg0, arg1)
}
#[export_name = "alibaba:fontkit/fontkit-interface#[method]font-kit.add-font-from-buffer"]
unsafe extern "C" fn export_method_font_kit_add_font_from_buffer(arg0: *mut u8,arg1: *mut u8,arg2: usize,) {
$($path_to_types)*::_export_method_font_kit_add_font_from_buffer_cabi::<<$ty as $($path_to_types)*::Guest>::FontKit>(arg0, arg1, arg2)
Expand Down Expand Up @@ -3345,63 +3362,64 @@ pub(crate) use __export_fontkit_impl as export;
#[cfg(target_arch = "wasm32")]
#[link_section = "component-type:wit-bindgen:0.25.0:fontkit:encoded world"]
#[doc(hidden)]
pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 2844] = *b"\
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\x9e\x15\x01A\x02\x01\
pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 2900] = *b"\
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xd6\x15\x01A\x02\x01\
A\x05\x01B\x06\x01k{\x01k\x7f\x01o\x02sv\x01p\x02\x01r\x05\x06weight\0\x06italic\
\x01\x07stretch\0\x06familys\x0avariations\x03\x04\0\x08font-key\x03\0\x04\x03\x01\
\x17alibaba:fontkit/commons\x05\0\x02\x03\0\0\x08font-key\x01B~\x02\x03\x02\x01\x01\
\x04\0\x08font-key\x03\0\0\x01r\x03\x02id{\x04names\x0blanguage-id{\x04\0\x04nam\
e\x03\0\x02\x01p\x03\x01ks\x01r\x04\x0bstyle-names\x04\x05names\x04\x04path\x05\x03\
key\x01\x04\0\x09font-info\x03\0\x06\x01r\x02\x08position|\x09thickness|\x04\0\x0c\
line-metrics\x03\0\x08\x04\0\x0ctext-metrics\x03\x01\x04\0\x0cglyph-bitmap\x03\x01\
\x04\0\x04font\x03\x01\x04\0\x08font-kit\x03\x01\x01i\x0a\x01@\x01\x05values\0\x0e\
\x04\0\x19[constructor]text-metrics\x01\x0f\x01h\x0a\x01@\x01\x04self\x10\0\x0e\x04\
\0\x1e[method]text-metrics.duplicate\x01\x11\x01@\x03\x04self\x10\x09font-sizev\x0e\
letter-spacingv\0v\x04\0\x1a[method]text-metrics.width\x01\x12\x01kv\x01@\x03\x04\
self\x10\x09font-sizev\x0bline-height\x13\0v\x04\0\x1b[method]text-metrics.heigh\
t\x01\x14\x01@\x02\x04self\x10\x09font-sizev\0v\x04\0\x1d[method]text-metrics.as\
cender\x01\x15\x01@\x01\x04self\x10\0v\x04\0\x1d[method]text-metrics.line-gap\x01\
\x16\x04\0\x1a[method]text-metrics.units\x01\x16\x01@\x03\x04self\x10\x05starty\x05\
county\0\x0e\x04\0\x1a[method]text-metrics.slice\x01\x17\x01@\x01\x04self\x10\0s\
\x04\0\x1a[method]text-metrics.value\x01\x18\x01@\x01\x04self\x10\0\x7f\x04\0\x1b\
[method]text-metrics.is-rtl\x01\x19\x01@\x02\x04self\x10\x05other\x0e\x01\0\x04\0\
\x1b[method]text-metrics.append\x01\x1a\x01@\x01\x04self\x10\0y\x04\0\x1a[method\
]text-metrics.count\x01\x1b\x01@\x03\x04self\x10\x05other\x0e\x08fallback\x7f\x01\
\0\x04\0\x1c[method]text-metrics.replace\x01\x1c\x01@\x04\x04self\x10\x09font-si\
zev\x0eletter-spacingv\x05widthv\0\x0e\x04\0#[method]text-metrics.split-by-width\
\x01\x1d\x01pt\x01@\x01\x04self\x10\0\x1e\x04\0\x1a[method]text-metrics.chars\x01\
\x1f\x01h\x0b\x01@\x01\x04self\x20\0y\x04\0\x1a[method]glyph-bitmap.width\x01!\x04\
\0\x1b[method]glyph-bitmap.height\x01!\x01p}\x01@\x01\x04self\x20\0\"\x04\0\x1b[\
method]glyph-bitmap.bitmap\x01#\x01@\x01\x04self\x20\0v\x04\0\x1a[method]glyph-b\
itmap.x-min\x01$\x04\0\x1a[method]glyph-bitmap.y-max\x01$\x04\0\x1d[method]glyph\
-bitmap.stroke-x\x01$\x04\0\x1d[method]glyph-bitmap.stroke-y\x01$\x01o\x02\"y\x01\
k%\x01@\x01\x04self\x20\0&\x04\0\"[method]glyph-bitmap.stroke-bitmap\x01'\x04\0\x1f\
[method]glyph-bitmap.advanced-x\x01$\x04\0\x1d[method]glyph-bitmap.ascender\x01$\
\x04\0\x1e[method]glyph-bitmap.descender\x01$\x01h\x0c\x01@\x02\x04self(\x01ct\0\
\x7f\x04\0\x16[method]font.has-glyph\x01)\x01@\x02\x04self(\x01ct\0\x05\x04\0\x1e\
[method]font.glyph-path-string\x01*\x01@\x01\x04self(\0\"\x04\0\x13[method]font.\
buffer\x01+\x01@\x01\x04self(\0s\x04\0\x11[method]font.path\x01,\x01@\x01\x04sel\
f(\0\x01\x04\0\x10[method]font.key\x01-\x01j\x01\x0e\x01s\x01@\x02\x04self(\x04t\
exts\0.\x04\0\x14[method]font.measure\x01/\x01@\x01\x04self(\0|\x04\0\x15[method\
]font.ascender\x010\x04\0\x16[method]font.descender\x010\x01@\x01\x04self(\0{\x04\
\0\x19[method]font.units-per-em\x011\x01i\x0b\x01k2\x01@\x04\x04self(\x01ct\x09f\
ont-sizev\x0cstroke-widthv\03\x04\0\x13[method]font.bitmap\x014\x01k\x09\x01@\x01\
\x04self(\05\x04\0\x1e[method]font.underline-metrics\x016\x01i\x0d\x01@\0\07\x04\
\0\x15[constructor]font-kit\x018\x01h\x0d\x01@\x02\x04self9\x06buffer\"\x01\0\x04\
\0%[method]font-kit.add-font-from-buffer\x01:\x01@\x02\x04self9\x04paths\x01\0\x04\
\0\x20[method]font-kit.add-search-path\x01;\x01i\x0c\x01k<\x01@\x02\x04self9\x03\
key\x01\0=\x04\0\x16[method]font-kit.query\x01>\x01p\x07\x01k?\x01@\x02\x04self9\
\x03key\x01\0\xc0\0\x04\0\x20[method]font-kit.query-font-info\x01A\x04\0\x1c[met\
hod]font-kit.exact-match\x01>\x01@\x01\x04self9\0?\x04\0\x1b[method]font-kit.fon\
ts-info\x01B\x01@\x01\x04self9\0y\x04\0\x14[method]font-kit.len\x01C\x01@\x02\x04\
self9\x03key\x01\x01\0\x04\0\x17[method]font-kit.remove\x01D\x01k\x0e\x01@\x03\x04\
self9\x03key\x01\x04texts\0\xc5\0\x04\0\x18[method]font-kit.measure\x01F\x01@\x01\
\x04self9\0s\x04\0\x1b[method]font-kit.write-data\x01G\x01@\x02\x04self9\x04data\
s\x01\0\x04\0\x1a[method]font-kit.read-data\x01H\x01@\x01\x05widths\0{\x04\0\x13\
str-width-to-number\x01I\x01@\x01\x05width{\0s\x04\0\x13number-width-to-str\x01J\
\x04\x01!alibaba:fontkit/fontkit-interface\x05\x02\x04\x01\x17alibaba:fontkit/fo\
ntkit\x04\0\x0b\x0d\x01\0\x07fontkit\x03\0\0\0G\x09producers\x01\x0cprocessed-by\
\x02\x0dwit-component\x070.208.1\x10wit-bindgen-rust\x060.25.0";
\x17alibaba:fontkit/commons\x05\0\x02\x03\0\0\x08font-key\x01B\x80\x01\x02\x03\x02\
\x01\x01\x04\0\x08font-key\x03\0\0\x01r\x03\x02id{\x04names\x0blanguage-id{\x04\0\
\x04name\x03\0\x02\x01p\x03\x01ks\x01r\x04\x0bstyle-names\x04\x05names\x04\x04pa\
th\x05\x03key\x01\x04\0\x09font-info\x03\0\x06\x01r\x02\x08position|\x09thicknes\
s|\x04\0\x0cline-metrics\x03\0\x08\x04\0\x0ctext-metrics\x03\x01\x04\0\x0cglyph-\
bitmap\x03\x01\x04\0\x04font\x03\x01\x04\0\x08font-kit\x03\x01\x01i\x0a\x01@\x01\
\x05values\0\x0e\x04\0\x19[constructor]text-metrics\x01\x0f\x01h\x0a\x01@\x01\x04\
self\x10\0\x0e\x04\0\x1e[method]text-metrics.duplicate\x01\x11\x01@\x03\x04self\x10\
\x09font-sizev\x0eletter-spacingv\0v\x04\0\x1a[method]text-metrics.width\x01\x12\
\x01kv\x01@\x03\x04self\x10\x09font-sizev\x0bline-height\x13\0v\x04\0\x1b[method\
]text-metrics.height\x01\x14\x01@\x02\x04self\x10\x09font-sizev\0v\x04\0\x1d[met\
hod]text-metrics.ascender\x01\x15\x01@\x01\x04self\x10\0v\x04\0\x1d[method]text-\
metrics.line-gap\x01\x16\x04\0\x1a[method]text-metrics.units\x01\x16\x01@\x03\x04\
self\x10\x05starty\x05county\0\x0e\x04\0\x1a[method]text-metrics.slice\x01\x17\x01\
@\x01\x04self\x10\0s\x04\0\x1a[method]text-metrics.value\x01\x18\x01@\x01\x04sel\
f\x10\0\x7f\x04\0\x1b[method]text-metrics.is-rtl\x01\x19\x01@\x02\x04self\x10\x05\
other\x0e\x01\0\x04\0\x1b[method]text-metrics.append\x01\x1a\x01@\x01\x04self\x10\
\0y\x04\0\x1a[method]text-metrics.count\x01\x1b\x01@\x03\x04self\x10\x05other\x0e\
\x08fallback\x7f\x01\0\x04\0\x1c[method]text-metrics.replace\x01\x1c\x01@\x04\x04\
self\x10\x09font-sizev\x0eletter-spacingv\x05widthv\0\x0e\x04\0#[method]text-met\
rics.split-by-width\x01\x1d\x01pt\x01@\x01\x04self\x10\0\x1e\x04\0\x1a[method]te\
xt-metrics.chars\x01\x1f\x01h\x0b\x01@\x01\x04self\x20\0y\x04\0\x1a[method]glyph\
-bitmap.width\x01!\x04\0\x1b[method]glyph-bitmap.height\x01!\x01p}\x01@\x01\x04s\
elf\x20\0\"\x04\0\x1b[method]glyph-bitmap.bitmap\x01#\x01@\x01\x04self\x20\0v\x04\
\0\x1a[method]glyph-bitmap.x-min\x01$\x04\0\x1a[method]glyph-bitmap.y-max\x01$\x04\
\0\x1d[method]glyph-bitmap.stroke-x\x01$\x04\0\x1d[method]glyph-bitmap.stroke-y\x01\
$\x01o\x02\"y\x01k%\x01@\x01\x04self\x20\0&\x04\0\"[method]glyph-bitmap.stroke-b\
itmap\x01'\x04\0\x1f[method]glyph-bitmap.advanced-x\x01$\x04\0\x1d[method]glyph-\
bitmap.ascender\x01$\x04\0\x1e[method]glyph-bitmap.descender\x01$\x01h\x0c\x01@\x02\
\x04self(\x01ct\0\x7f\x04\0\x16[method]font.has-glyph\x01)\x01@\x02\x04self(\x01\
ct\0\x05\x04\0\x1e[method]font.glyph-path-string\x01*\x01@\x01\x04self(\0\"\x04\0\
\x13[method]font.buffer\x01+\x01@\x01\x04self(\0s\x04\0\x11[method]font.path\x01\
,\x01@\x01\x04self(\0\x01\x04\0\x10[method]font.key\x01-\x01j\x01\x0e\x01s\x01@\x02\
\x04self(\x04texts\0.\x04\0\x14[method]font.measure\x01/\x01@\x01\x04self(\0|\x04\
\0\x15[method]font.ascender\x010\x04\0\x16[method]font.descender\x010\x01@\x01\x04\
self(\0{\x04\0\x19[method]font.units-per-em\x011\x01i\x0b\x01k2\x01@\x04\x04self\
(\x01ct\x09font-sizev\x0cstroke-widthv\03\x04\0\x13[method]font.bitmap\x014\x01k\
\x09\x01@\x01\x04self(\05\x04\0\x1e[method]font.underline-metrics\x016\x01i\x0d\x01\
@\0\07\x04\0\x15[constructor]font-kit\x018\x01h\x0d\x01@\x02\x04self9\x05limity\x01\
\0\x04\0\x1e[method]font-kit.set-lru-limit\x01:\x01@\x02\x04self9\x06buffer\"\x01\
\0\x04\0%[method]font-kit.add-font-from-buffer\x01;\x01@\x02\x04self9\x04paths\x01\
\0\x04\0\x20[method]font-kit.add-search-path\x01<\x01i\x0c\x01k=\x01@\x02\x04sel\
f9\x03key\x01\0>\x04\0\x16[method]font-kit.query\x01?\x01p\x07\x01k\xc0\0\x01@\x02\
\x04self9\x03key\x01\0\xc1\0\x04\0\x20[method]font-kit.query-font-info\x01B\x04\0\
\x1c[method]font-kit.exact-match\x01?\x01@\x01\x04self9\0\xc0\0\x04\0\x1b[method\
]font-kit.fonts-info\x01C\x01@\x01\x04self9\0y\x04\0\x14[method]font-kit.len\x01\
D\x01@\x02\x04self9\x03key\x01\x01\0\x04\0\x17[method]font-kit.remove\x01E\x01k\x0e\
\x01@\x03\x04self9\x03key\x01\x04texts\0\xc6\0\x04\0\x18[method]font-kit.measure\
\x01G\x01@\x01\x04self9\0s\x04\0\x1b[method]font-kit.write-data\x01H\x01@\x02\x04\
self9\x04datas\x01\0\x04\0\x1a[method]font-kit.read-data\x01I\x01@\x01\x05widths\
\0{\x04\0\x13str-width-to-number\x01J\x01@\x01\x05width{\0s\x04\0\x13number-widt\
h-to-str\x01K\x04\x01!alibaba:fontkit/fontkit-interface\x05\x02\x04\x01\x17aliba\
ba:fontkit/fontkit\x04\0\x0b\x0d\x01\0\x07fontkit\x03\0\0\0G\x09producers\x01\x0c\
processed-by\x02\x0dwit-component\x070.208.1\x10wit-bindgen-rust\x060.25.0";

#[inline(never)]
#[doc(hidden)]
Expand Down
24 changes: 22 additions & 2 deletions src/font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::hash::Hash;
#[cfg(feature = "parse")]
use std::io::Read;
use std::path::PathBuf;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
pub use ttf_parser::LineMetrics;
use ttf_parser::{Face, Fixed, Tag, VariationAxis, Width as ParserWidth};
Expand Down Expand Up @@ -400,6 +401,8 @@ pub(crate) struct Font {
buffer: ArcSwap<Vec<u8>>,
/// [Font variation](https://learn.microsoft.com/en-us/typography/opentype/spec/fvar) and font collection data
variants: Vec<VariationData>,
hit_counter: Arc<AtomicU32>,
pub(crate) hit_index: AtomicU32,
}

impl Font {
Expand All @@ -416,7 +419,10 @@ impl Font {
}

#[cfg(feature = "parse")]
pub(super) fn from_buffer(mut buffer: Vec<u8>) -> Result<Self, Error> {
pub(super) fn from_buffer(
mut buffer: Vec<u8>,
hit_counter: Arc<AtomicU32>,
) -> Result<Self, Error> {
let mut variants = vec![0];
if is_otf(&buffer) {
variants = (0..ttf_parser::fonts_in_collection(&buffer).unwrap_or(1)).collect();
Expand Down Expand Up @@ -448,6 +454,8 @@ impl Font {
path: None,
buffer: ArcSwap::new(Arc::new(buffer)),
variants,
hit_index: AtomicU32::default(),
hit_counter,
})
}

Expand All @@ -459,6 +467,8 @@ impl Font {
if !self.buffer.load().is_empty() {
return Ok(());
}
let hit_index = self.hit_counter.fetch_add(1, Ordering::SeqCst);
self.hit_index.store(hit_index, Ordering::SeqCst);
#[cfg(feature = "parse")]
if let Some(path) = self.path.as_ref() {
let mut buffer = Vec::new();
Expand Down Expand Up @@ -525,13 +535,23 @@ impl Font {
&self.variants
}

pub(super) fn new(path: Option<PathBuf>, variants: Vec<VariationData>) -> Self {
pub(super) fn new(
path: Option<PathBuf>,
variants: Vec<VariationData>,
hit_counter: Arc<AtomicU32>,
) -> Self {
Font {
path,
variants,
buffer: ArcSwap::default(),
hit_index: AtomicU32::default(),
hit_counter,
}
}

pub(super) fn buffer_size(&self) -> usize {
self.buffer.load().len()
}
}

#[self_referencing]
Expand Down
Loading

0 comments on commit 10ea022

Please sign in to comment.