创建全局字体缓存
Create a global font cache
我正在使用 rustybuzz and wasm-bindgen 在 HTML5 canvas 上排版文本。我想创建一个全局字体缓存,由 String
s 索引,这样我就可以加载和解析一次字体文件,然后多次重用它们(提示关于全局变量有多糟糕的评论......如果有人有更好的方法,请告诉我)。具体来说,我想要可以在任何地方访问的 HashMap<String, rustybuzz::Face>
的一些变体。然后我想在 JavaScript 端公开一个 register_font
函数,这样我就可以加载 ArrayBuffers
,比如:
#[wasm_bindgen]
pub fn register_font(name: &str, font_data: &[u8]) {
MY_FONT_CACHE_SOMEHOW.insert(
name.to_string(),
rustybuzz::Face::from_slice(&font_data, 0).unwrap()
);
}
并且,为了完成,我想要一个内部 get_font
函数来检索:
fn get_font(name: &String) -> rustybuzz::Face {
MY_FONT_CACHE_SOMEHOW.get(name).unwrap()
}
我知道我遇到了可变生命周期的问题,只是不知道如何解决。 rustybuzz::Face
结构只是引用它的内部数据,它并不拥有它。 wasm-bindgen
不支持将 register_font
函数上的传入 ArrayBuffer
/[u8]
标记为 'static
,这似乎是主要问题之一。但是我对这整个生锈的事情还是陌生的。任何人都知道如何做到这一点(或更好的方法)?
如果你只添加到散列 table 而从不删除你可以复制和泄漏 font_data 使其静态:
#[wasm_bindgen]
pub fn register_font(name: &str, font_data: &[u8]) {
let font_data: &'static [u8] = font_data.to_owned().leak();
//...
}
如果您希望能够从缓存中删除字体,您必须将 font_data
和 Face
放在一起。那就是臭名昭著的 self-referential type
.
问题
您可以采取不安全的方式并保留指向动态分配的 *const [u8]
类型的指针,或者您可以使用试图解决此问题的众多 crate 之一。
目前我最喜欢的是ouroboros
:应该是这样的(未测试):
#[self_referencing]
struct MyFace {
font_data: Vec<u8>,
#[borrows(font_data)]
face: Face<'this>,
}
#[wasm_bindgen]
pub fn register_font(name: &str, font_data: &[u8]) {
let face = MyFaceBuilder {
font_data: font_data.to_owned(),
face_builder: |font_data: &[u8]| Face::from_slice(font_data).unwrap(),
}.build();
MY_FONT_CACHE_SOMEHOW.insert(
name.to_string(),
face,
);
}
我正在使用 rustybuzz and wasm-bindgen 在 HTML5 canvas 上排版文本。我想创建一个全局字体缓存,由 String
s 索引,这样我就可以加载和解析一次字体文件,然后多次重用它们(提示关于全局变量有多糟糕的评论......如果有人有更好的方法,请告诉我)。具体来说,我想要可以在任何地方访问的 HashMap<String, rustybuzz::Face>
的一些变体。然后我想在 JavaScript 端公开一个 register_font
函数,这样我就可以加载 ArrayBuffers
,比如:
#[wasm_bindgen]
pub fn register_font(name: &str, font_data: &[u8]) {
MY_FONT_CACHE_SOMEHOW.insert(
name.to_string(),
rustybuzz::Face::from_slice(&font_data, 0).unwrap()
);
}
并且,为了完成,我想要一个内部 get_font
函数来检索:
fn get_font(name: &String) -> rustybuzz::Face {
MY_FONT_CACHE_SOMEHOW.get(name).unwrap()
}
我知道我遇到了可变生命周期的问题,只是不知道如何解决。 rustybuzz::Face
结构只是引用它的内部数据,它并不拥有它。 wasm-bindgen
不支持将 register_font
函数上的传入 ArrayBuffer
/[u8]
标记为 'static
,这似乎是主要问题之一。但是我对这整个生锈的事情还是陌生的。任何人都知道如何做到这一点(或更好的方法)?
如果你只添加到散列 table 而从不删除你可以复制和泄漏 font_data 使其静态:
#[wasm_bindgen]
pub fn register_font(name: &str, font_data: &[u8]) {
let font_data: &'static [u8] = font_data.to_owned().leak();
//...
}
如果您希望能够从缓存中删除字体,您必须将 font_data
和 Face
放在一起。那就是臭名昭著的 self-referential type
.
您可以采取不安全的方式并保留指向动态分配的 *const [u8]
类型的指针,或者您可以使用试图解决此问题的众多 crate 之一。
目前我最喜欢的是ouroboros
:应该是这样的(未测试):
#[self_referencing]
struct MyFace {
font_data: Vec<u8>,
#[borrows(font_data)]
face: Face<'this>,
}
#[wasm_bindgen]
pub fn register_font(name: &str, font_data: &[u8]) {
let face = MyFaceBuilder {
font_data: font_data.to_owned(),
face_builder: |font_data: &[u8]| Face::from_slice(font_data).unwrap(),
}.build();
MY_FONT_CACHE_SOMEHOW.insert(
name.to_string(),
face,
);
}